[HNOI2014]世界树
· 题解
参考hzwer
首先看到Mi的条件想到构造虚树。
虚树中的一条边已经覆盖了整个出现在这条边上的点的子树的情况。
那么只需倍增查找所属议事处有变化的边界节点,同时计算这两段节点的贡献即可。
· 代码
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <vector> 5 #include <algorithm> 6 7 using namespace std; 8 9 const int MAXN = 3e05 + 10; 10 const int MAXM = 3e05 + 10; 11 12 struct LinkedForwardStar { 13 int to; 14 15 int next; 16 } ; 17 18 LinkedForwardStar Link[MAXM << 1]; 19 int Head[MAXN]= {0}; 20 int size = 0; 21 22 void Insert (int u, int v) { 23 Link[++ size].to = v; 24 Link[size].next = Head[u]; 25 26 Head[u] = size; 27 } 28 29 const int Root = 1; 30 31 int Deep[MAXN]; 32 33 int Size[MAXN]; 34 35 int Dfn[MAXN]; 36 int dfsord = 0; 37 38 int Father[MAXN][23]; 39 40 void DFS (int root, int father) { 41 Dfn[root] = ++ dfsord; 42 Size[root] = 1; 43 Father[root][0] = father; 44 for (int j = 1; j <= 20; j ++) { 45 if (! Father[root][j - 1]) 46 continue; 47 48 Father[root][j] = Father[Father[root][j - 1]][j - 1]; 49 } 50 51 for (int i = Head[root]; i; i = Link[i].next) { 52 int v = Link[i].to; 53 54 if (v == father) 55 continue; 56 57 Deep[v] = Deep[root] + 1; 58 59 DFS (v, root); 60 61 Size[root] += Size[v]; 62 } 63 } 64 65 int LCA (int x, int y) { 66 if (Deep[x] < Deep[y]) 67 swap (x, y); 68 69 int fx = x, fy = y; 70 for (int j = 20; j >= 0; j --) 71 if (Deep[Father[fx][j]] >= Deep[fy]) 72 fx = Father[fx][j]; 73 74 if (fx == fy) 75 return fy; 76 77 for (int j = 20; j >= 0; j --) 78 if (Father[fx][j] != Father[fy][j]) { 79 fx = Father[fx][j]; 80 fy = Father[fy][j]; 81 } 82 83 return Father[fx][0]; 84 } 85 86 int Dist (int x, int y) { 87 int lca = LCA (x, y); 88 return Deep[x] + Deep[y] - 2 * Deep[lca]; 89 } 90 91 int N, Q; 92 93 int A[MAXN]; 94 95 vector<int> Graph[MAXN]; 96 97 int Stack[MAXN]; 98 int top = 0; 99 100 int Belong[MAXN]= {0}; 101 102 bool comp (const int& a, const int& b) { 103 return Dfn[a] < Dfn[b]; 104 } 105 106 void Insert_IvTree (int p) { 107 if (! top) { 108 Stack[++ top] = p; 109 110 return ; 111 } 112 113 int lca = 0; 114 while (top > 0) { 115 lca = LCA (Stack[top], p); 116 if (top > 1 && Deep[lca] < Deep[Stack[top - 1]]) 117 Graph[Stack[top - 1]].push_back(Stack[top]), top --; 118 else if (Deep[lca] < Deep[Stack[top]]) { 119 Graph[lca].push_back(Stack[top]), top --; 120 break; 121 } 122 else 123 break; 124 } 125 126 if (Stack[top] != lca) 127 Stack[++ top] = lca; 128 Stack[++ top] = p; 129 } 130 131 int M; 132 133 void Construct () { 134 top = 0; 135 if (Belong[Root] != Root) 136 Stack[++ top] = Root; 137 138 sort (A + 1, A + M + 1, comp); 139 140 for (int i = 1; i <= M; i ++) 141 Insert_IvTree (A[i]); 142 while (top > 1) 143 Graph[Stack[top - 1]].push_back(Stack[top]), top --; 144 } 145 146 int Rank[MAXN]= {0}; 147 148 int Rest[MAXN]= {0}; 149 150 void Get_BelSon (int root) { 151 Rank[++ dfsord] = root; 152 Rest[root] = Size[root]; 153 154 for (int i = 0; i < Graph[root].size(); i ++) { 155 int v = Graph[root][i]; 156 157 Get_BelSon (v); 158 159 if (! Belong[v]) 160 continue; 161 162 int dist1 = Dist (Belong[root], root), dist2 = Dist (Belong[v], root); 163 if (! Belong[root] || dist1 > dist2 || (dist1 == dist2 && Belong[root] > Belong[v])) 164 Belong[root] = Belong[v]; 165 } 166 } 167 168 void Get_BelFat (int root) { 169 for (int i = 0; i < Graph[root].size(); i ++) { 170 int v = Graph[root][i]; 171 172 int dist1 = Dist (Belong[root], v), dist2 = Dist (Belong[v], v); 173 if (! Belong[v] || dist1 < dist2 || (dist1 == dist2 && Belong[root] < Belong[v])) 174 Belong[v] = Belong[root]; 175 176 Get_BelFat (v); 177 } 178 } 179 180 int Count[MAXN]= {0}; 181 182 void Calc (int u, int v) { 183 int p = v; 184 for (int j = 20; j >= 0; j --) 185 if (Deep[Father[p][j]] > Deep[u]) 186 p = Father[p][j]; 187 188 Rest[u] -= Size[p]; 189 190 if (Belong[u] == Belong[v]) { 191 Count[Belong[u]] += Size[p] - Size[v]; 192 return ; 193 } 194 195 int mid = v; 196 for (int j = 20; j >= 0; j --) { 197 if (Deep[Father[mid][j]] <= Deep[u]) 198 continue; 199 200 int nextpos = Father[mid][j]; 201 int dist1 = Dist (Belong[v], nextpos), dist2 = Dist (Belong[u], nextpos); 202 if (dist1 < dist2 || (dist1 == dist2 && Belong[v] < Belong[u])) 203 mid = nextpos; 204 } 205 206 Count[Belong[u]] += Size[p] - Size[mid]; 207 Count[Belong[v]] += Size[mid] - Size[v]; 208 } 209 210 int getnum () { 211 int num = 0; 212 char ch = getchar (); 213 214 while (! isdigit (ch)) 215 ch = getchar (); 216 while (isdigit (ch)) 217 num = num * 10 + ch - '0', ch = getchar (); 218 219 return num; 220 } 221 222 int Orig[MAXN]; 223 224 void Solve () { 225 M = getnum (); 226 227 for (int i = 1; i <= M; i ++) 228 A[i] = Orig[i] = getnum (); 229 230 for (int i = 1; i <= M; i ++) 231 Belong[A[i]] = A[i]; 232 233 Construct (); 234 235 dfsord = 0; 236 Get_BelSon (Root), Get_BelFat (Root); 237 238 for (int i = 1; i <= dfsord; i ++) { 239 int u = Rank[i]; 240 for (int j = 0; j < Graph[u].size(); j ++) { 241 int v = Graph[u][j]; 242 Calc (u, v); 243 } 244 } 245 246 for (int i = 1; i <= dfsord; i ++) 247 Count[Belong[Rank[i]]] += Rest[Rank[i]]; 248 249 for (int i = 1; i <= M; i ++) { 250 if (i > 1) 251 putchar (' '); 252 printf ("%d", Count[Orig[i]]); 253 } 254 puts (""); 255 256 for (int i = 1; i <= dfsord; i ++) { 257 Graph[Rank[i]].clear(); 258 Count[Rank[i]] = Belong[Rank[i]] = Rest[Rank[i]] = 0; 259 } 260 } 261 262 int main () { 263 N = getnum (); 264 265 for (int i = 1; i < N; i ++) { 266 int u, v; 267 u = getnum (), v = getnum (); 268 269 Insert (u, v), Insert (v, u); 270 } 271 272 Deep[Root] = 1; 273 DFS (Root, 0); 274 275 Q = getnum (); 276 277 for (int Case = 1; Case <= Q; Case ++) 278 Solve (); 279 280 return 0; 281 } 282 283 /* 284 10 285 2 1 286 3 2 287 4 3 288 5 4 289 6 1 290 7 3 291 8 3 292 9 4 293 10 1 294 5 295 2 296 6 1 297 5 298 2 7 3 6 9 299 1 300 8 301 4 302 8 7 10 3 303 5 304 2 9 3 5 8 305 */