1. 程式人生 > >Codeforces 600E - Lomsat gelral 「$Dsu \ on \ tree$模板」

Codeforces 600E - Lomsat gelral 「$Dsu \ on \ tree$模板」

With $Dsu \ on \ tree$ we can answer queries of this type:

How many vertices in the subtree of vertex $v$ has some property in $O (n \log n)$ time (for all of the queries)?

這題寫的是輕重兒子(重鏈剖分)版本的 $Dsu \ on \ tree$

具體流程如下:

每次先遞迴計算輕兒子,再單獨遞迴重兒子,計算完後輕兒子的一些資訊需要刪掉,但是重兒子的資訊無需刪除,如此出解,相當於是優化了暴力的多餘部分

每個節點會作為輕兒子被計算,重鏈剖分上垂直有 $\log n$ 條鏈,故複雜度 $O (n \log n)$

程式碼

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 
  5 using namespace std;
  6 
  7 typedef long long LL;
  8 
  9 const int MAXN = 1e05 + 10;
 10 const int MAXM = 1e05 + 10;
 11 const int
MAXC = 1e05 + 10; 12 13 struct LinkedForwardStar { 14 int to; 15 16 int next; 17 } ; 18 19 LinkedForwardStar Link[MAXM << 1]; 20 int Head[MAXN]= {0}; 21 int size = 0; 22 23 void Insert (int u, int v) { 24 Link[++ size].to = v; 25 Link[size].next = Head[u];
26 27 Head[u] = size; 28 } 29 30 int N; 31 int colour[MAXN]; 32 33 int son[MAXN]= {0}; 34 int subsize[MAXN]= {0}; 35 void DFS (int root, int father) { 36 son[root] = - 1; 37 subsize[root] = 1; 38 for (int i = Head[root]; i; i = Link[i].next) { 39 int v = Link[i].to; 40 if (v == father) 41 continue; 42 DFS (v, root); 43 subsize[root] += subsize[v]; 44 if (son[root] == - 1 || subsize[v] > subsize[son[root]]) 45 son[root] = v; 46 } 47 } 48 int vis[MAXN]= {0}; 49 int total[MAXC]= {0}; 50 int maxv = 0; 51 LL sum = 0; 52 void calc (int root, int father, int delta) { // 統計答案 53 total[colour[root]] += delta; 54 if (delta > 0 && total[colour[root]] >= maxv) { 55 if (total[colour[root]] > maxv) 56 sum = 0, maxv = total[colour[root]]; 57 sum += colour[root]; 58 } 59 for (int i = Head[root]; i; i = Link[i].next) { 60 int v = Link[i].to; 61 if (v == father || vis[v]) 62 continue; 63 calc (v, root, delta); 64 } 65 } 66 LL answer[MAXN]= {0}; 67 void Solve (int root, int father, int type) { // type表示是不是重兒子資訊 68 for (int i = Head[root]; i; i = Link[i].next) { 69 int v = Link[i].to; 70 if (v == father || v == son[root]) 71 continue; 72 Solve (v, root, 0); 73 } 74 if (~ son[root]) 75 Solve (son[root], root, 1), vis[son[root]] = 1; 76 calc (root, father, 1); 77 answer[root] = sum; 78 if (~ son[root]) 79 vis[son[root]] = 0; 80 if (! type) // 如果是輕兒子資訊就需刪除 81 calc (root, father, - 1), maxv = sum = 0; 82 } 83 84 int getnum () { 85 int num = 0; 86 char ch = getchar (); 87 88 while (! isdigit (ch)) 89 ch = getchar (); 90 while (isdigit (ch)) 91 num = (num << 3) + (num << 1) + ch - '0', ch = getchar (); 92 93 return num; 94 } 95 96 int main () { 97 N = getnum (); 98 for (int i = 1; i <= N; i ++) 99 colour[i] = getnum (); 100 for (int i = 1; i < N; i ++) { 101 int u = getnum (), v = getnum (); 102 Insert (u, v), Insert (v, u); 103 } 104 DFS (1, 0), Solve (1, 0, 0); 105 for (int i = 1; i <= N; i ++) { 106 if (i > 1) 107 putchar (' '); 108 printf ("%lld", answer[i]); 109 } 110 puts (""); 111 112 return 0; 113 } 114 115 /* 116 4 117 1 2 3 4 118 1 2 119 2 3 120 2 4 121 */ 122 123 /* 124 15 125 1 2 3 1 2 3 3 1 1 3 2 2 1 2 3 126 1 2 127 1 3 128 1 4 129 1 14 130 1 15 131 2 5 132 2 6 133 2 7 134 3 8 135 3 9 136 3 10 137 4 11 138 4 12 139 4 13 140 */