Codeforces 337D Book of Evil:树的直径【结论】

题目链接: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 }

 

posted @ 2018-01-05 15:33  Leohh  阅读(259)  评论(0编辑  收藏  举报