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