Codeforces 337D Book of Evil:樹的直徑【結論】

Leohh發表於2018-01-05

題目連結:http://codeforces.com/problemset/problem/337/D

題意:

  給你一棵樹,n個節點。

  如果一個節點處放著“罪惡之書”,那麼它會影響周圍距離不超過d的所有節點。

  然後告訴你一部分被影響的節點aff[i],共m個。

  已知有且僅有一個節點放著“罪惡之書”。

  現在問你有多少個節點可能放著“罪惡之書”。

 

題解:

  如果一個節點放著“罪惡之書”,那麼它到所有aff[i]的距離都不超過d。

  也就是:max(它到aff[i]的距離) <= d

 

  有一個關於樹的直徑的結論:

    從一個點出發,不重複經過節點,若要使走的路程最遠,則最終到達的點一定是樹的直徑的某個端點。

  在這道題中就是:

    從一個點出發,若到達aff[i]的距離在所有受影響的節點中最大。

    則節點i一定是受影響的點中,兩兩距離最遠的一對點(op,ed)中的一個。

 

  所以要找出在aff[i]中,兩兩距離最遠的一對點(op,ed)。

  也就是求所有aff[i]構成的一棵樹的直徑:

    先隨便找一個aff[i],從它開始dfs1一遍,找出最遠的點即為op。

    再從op開始,dfs1一遍,找出ed。

 

  然後從op和ed分別做一次dfs2,給每個距離不超過d的點的cnt加1。

  最後統計一下cnt為2的點的個數,即為答案。

 

AC Code:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <vector>
 5 #define MAX_N 100005
 6 
 7 using namespace std;
 8 
 9 int n,m,d;
10 int maxd;
11 int op,ed;
12 int aff[MAX_N];
13 int cnt[MAX_N];
14 bool flag[MAX_N];
15 vector<int> edge[MAX_N];
16 
17 void read()
18 {
19     cin>>n>>m>>d;
20     memset(flag,false,sizeof(flag));
21     for(int i=1;i<=m;i++)
22     {
23         cin>>aff[i];
24         flag[aff[i]]=true;
25     }
26     int x,y;
27     for(int i=1;i<n;i++)
28     {
29         cin>>x>>y;
30         edge[x].push_back(y);
31         edge[y].push_back(x);
32     }
33 }
34 
35 void dfs1(int now,int p,int nd,int &v)
36 {
37     if(nd>maxd && flag[now])
38     {
39         maxd=nd;
40         v=now;
41     }
42     for(int i=0;i<edge[now].size();i++)
43     {
44         int temp=edge[now][i];
45         if(temp!=p)
46         {
47             dfs1(temp,now,nd+1,v);
48         }
49     }
50 }
51 
52 void dfs2(int now,int p,int stp)
53 {
54     if(stp>d) return;
55     cnt[now]++;
56     for(int i=0;i<edge[now].size();i++)
57     {
58         int temp=edge[now][i];
59         if(temp!=p) dfs2(temp,now,stp+1);
60     }
61 }
62 
63 void work()
64 {
65     maxd=-1;
66     dfs1(aff[1],-1,0,op);
67     maxd=-1;
68     dfs1(op,-1,0,ed);
69     memset(cnt,0,sizeof(cnt));
70     dfs2(op,-1,0);
71     dfs2(ed,-1,0);
72     int ans=0;
73     for(int i=1;i<=n;i++)
74     {
75         if(cnt[i]==2) ans++;
76     }
77     cout<<ans<<endl;
78 }
79 
80 int main()
81 {
82     read();
83     work();
84 }

 

相關文章