CodeForces 337D Book of Evil

题目链接:http://codeforces.com/contest/337/problem/D

题目大意:

  给定一棵树,树的某个节点存在一本恶魔之书,能使所有到该点的距离小于d的所有点出现幽灵,现在给出m个出现幽灵的点,问可能存在恶魔之书的节点有多少个。

分析:

  先找出相距最远的2个幽灵节点(由于每条边的距离为1,所以可以用bfs,不然就只能用Dijkstra),然后各自以幽灵节点自身为中心,向外bfs C层(C <= d),把这些层的节点都放入一个集合,最后两个集合求交就是答案了。
  由于是树型结构,所以只要包含了相距最远的2个幽灵节点就包含了所有幽灵节点,可以用反证法证明。
  幽灵节点本身也有可能放书。

代码如下:

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3  
  4 #define rep(i,n) for (int i = 0; i < (n); ++i)
  5 #define For(i,s,t) for (int i = (s); i <= (t); ++i)
  6 #define rFor(i,t,s) for (int i = (t); i >= (s); --i)
  7 #define foreach(i,c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i)
  8 #define rforeach(i,c) for (__typeof(c.rbegin()) i = c.rbegin(); i != c.rend(); ++i)
  9  
 10 #define pr(x) cout << #x << " = " << x << "  "
 11 #define prln(x) cout << #x << " = " << x << endl
 12  
 13 #define LOWBIT(x) ((x)&(-x))
 14  
 15 #define ALL(x) x.begin(),x.end()
 16 #define INS(x) inserter(x,x.begin())
 17  
 18 #define ms0(a) memset(a,0,sizeof(a))
 19 #define msI(a) memset(a,inf,sizeof(a))
 20 #define msM(a) memset(a,-1,sizeof(a))
 21  
 22 #define pii pair<int,int> 
 23 #define piii pair<pair<int,int>,int> 
 24 #define mp make_pair
 25 #define pb push_back
 26 #define fi first
 27 #define se second
 28  
 29 inline int gc(){
 30     static const int BUF = 1e7;
 31     static char buf[BUF], *bg = buf + BUF, *ed = bg;
 32      
 33     if(bg == ed) fread(bg = buf, 1, BUF, stdin);
 34     return *bg++;
 35 } 
 36  
 37 inline int ri(){
 38     int x = 0, f = 1, c = gc();
 39     for(; c<48||c>57; f = c=='-'?-1:f, c=gc());
 40     for(; c>47&&c<58; x = x*10 + c - 48, c=gc());
 41     return x*f;
 42 }
 43  
 44 typedef long long LL;
 45 typedef unsigned long long uLL;
 46 const int inf = 1e9 + 9;
 47 const LL mod = 1e9 + 7;
 48 const int maxN = 1e5 + 7;
 49  
 50 struct Node{
 51     vector< int > next;
 52 };
 53  
 54 int n, m, d, ans;
 55 int vis[maxN];
 56 int ghost[maxN]; // 记录是否是幽灵 
 57 int state[maxN]; // 标记是否可能存在书,值为2的时候才存在 
 58 Node nodes[maxN];
 59 queue< int > Q;
 60  
 61 int g_1, g_2; // 最远幽灵点对 
 62  
 63 // 返回与幽灵节点x距离最远的幽灵节点的幽灵节点序号 
 64 int bfs_1(int x) {
 65     int dist = 1;
 66     int cnt = m - 1, cnt_1 = 1;
 67     if(cnt == 0) return x;
 68     while(!Q.empty()) Q.pop();
 69     ms0(vis);
 70     vis[x] = 1; 
 71     Q.push(x);
 72      
 73     while(!Q.empty()) {
 74         --cnt_1;
 75         if(dist > 2 * d) return -1;
 76         int tmp = Q.front();
 77         Q.pop();
 78          
 79         foreach(i, nodes[tmp].next) {
 80             if(vis[*i]) continue;
 81             vis[*i] = 1;
 82             if(ghost[*i] == 1) {
 83                 --cnt;
 84                 if(cnt == 0) return *i;
 85             }
 86             Q.push(*i);
 87         }
 88         if(cnt_1 == 0) {
 89             ++dist;
 90             cnt_1 = Q.size();
 91         }
 92     }
 93 }
 94  
 95 // 以幽灵节点x为中心,向外bfs,记录所有与x距离小于等于d的节点,自身节点也算 
 96 void bfs_2(int x) {
 97     int dist = 1, cnt_1 = 1;
 98     while(!Q.empty()) Q.pop();
 99     ms0(vis);
100     vis[x] = 1; 
101     Q.push(x);
102     ++state[x];
103      
104     while(!Q.empty()) {
105         --cnt_1;
106         if(dist > d) return;
107         int tmp = Q.front();
108         Q.pop();
109          
110         foreach(i, nodes[tmp].next) {
111             if(vis[*i]) continue;
112             vis[*i] = 1;
113             ++state[*i];
114             Q.push(*i);
115         }
116         if(cnt_1 == 0) {
117             ++dist;
118             cnt_1 = Q.size();
119         }
120     }
121 }
122  
123 int main(){
124     cin >> n >> m >> d;
125     For(i, 1, m) {
126         cin >> g_1;
127         ghost[g_1] = 1;
128     }
129      
130     For(i, 1, n-1) {
131         int x, y;
132         cin >> x >> y;
133         nodes[x].next.push_back(y);
134         nodes[y].next.push_back(x);
135     }
136      
137     g_2 = bfs_1(g_1); 
138     g_1 = bfs_1(g_2); 
139      
140     if(g_1 != -1 && g_2 != -1) {
141         bfs_2(g_1);
142         bfs_2(g_2);
143          
144         For(i, 1, n) if(state[i] == 2) ++ans;
145     }
146      
147     cout << ans << endl;
148     return 0;
149 }
150  
151 /*
152 25 7 8
153 2 6 9 13 20 17 23
154 1 2
155 1 3
156 1 4
157 2 5
158 5 8
159 5 9
160 8 15
161 9 16
162 3 6
163 6 10
164 6 11
165 6 12
166 6 13
167 11 17
168 17 22
169 17 23
170 12 18
171 4 7
172 7 14
173 14 19
174 14 20
175 20 24
176 20 25
177 14 21
178  
179 ans: 16
180 */
View Code

 

posted @ 2019-04-22 19:58  梦樱羽  阅读(222)  评论(0编辑  收藏  举报
Live2D