首先有一道题
王室联邦
题目大意
给定一棵树,将树分为大小范围为 $[B, 3B]$ 的连通块集,求方案
树上分块方法之一
类似贪心,用栈维护还没有在连通块中的子节点,对于递归到的当前的点 $p$ ,扫描它的子树,能拼凑就拼凑
但是注意最后可能还会有一些点(一定包括根)剩下,那么将这些点并到最后一个连通块即可
显然每个连通块都满足大小为 $[B, 3B]$
核心代码
void DFS (int root, int father) { int bot = top; for (int i = Head[root]; i; i = Link[i].next) { int v = Link[i].to; if (v == father) continue; DFS (v, root); if (top - bot >= B) { capt[++ bind] = root; while (top > bot) belong[Stack[top --]] = bind; } } Stack[++ top] = root; }
树上莫队
首先用王室联邦的方法将树分块
用一个数组 $state_p$ 来维护 $p$ 点是否在当前询问的路径上,那么每次访问就将 $state_p$ 翻转,顺便修改 $ans$ ,相当于原序列上莫队的 $add, del$ 操作
那么,每次需要修改那些点呢?
假设当前处理到 $(px, py)$ ,现在需要处理 $(x, y)$ ,那么只需修改 $px$ 到 $x$ 以及 $py$ 到 $y$ 的路径上的点即可
接下来证明该操作的正确性:
令 $T (x, y)$ 表示 $x$ 到 $y$ 路径上的点集, $xor$ 操作类似位运算的异或,即有相同点则删去,无则加入
则有 $T (x, y) = T (x, root) xor T (y, root)$ (注意,这里的 $T (x, y)$ 是不包括 $lca$ 的,故 $lca$ 需单独处理)
接下来是证明
$egin{aligned} &T (px, py) xor T (x, y) \ &= [T (px, root) xor T (py, root)] xor [T (x, root) xor T (y, root)] \ &= [T (px, root) xor T (x, root)] xor [T (py, root) xor T (y, root)] \ &= T (px, x) xor T (py, y) end{aligned}$
那么其它的修改什么的就和序列上莫队一样了
例题
代码
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <cmath> 6 7 using namespace std; 8 9 typedef long long LL; 10 11 const int MAXN = 1e05 + 10; 12 const int MAXM = 1e05 + 10; 13 const int MAXQ = 1e05 + 10; 14 15 struct LinkedForwardStar { 16 int to; 17 18 int next; 19 } ; 20 21 LinkedForwardStar Link[MAXM << 1]; 22 int Head[MAXN]= {0}; 23 int size = 0; 24 25 void Insert (int u, int v) { 26 Link[++ size].to = v; 27 Link[size].next = Head[u]; 28 29 Head[u] = size; 30 } 31 32 int N, M, Q; 33 LL V[MAXN], W[MAXN]; 34 int pcol[MAXN]; 35 int limit; 36 37 int belong[MAXN]; 38 int lind = 0; 39 int Stack[MAXN]; 40 int top = 0; 41 void DFS_bel (int root, int father) { 42 int bot = top; 43 for (int i = Head[root]; i; i = Link[i].next) { 44 int v = Link[i].to; 45 if (v == father) 46 continue; 47 DFS_bel (v, root); 48 if (top - bot >= limit) { 49 lind ++; 50 while (top > bot) 51 belong[Stack[top --]] = lind; 52 } 53 } 54 Stack[++ top] = root; 55 } 56 57 int father[MAXN]= {0}; 58 int deep[MAXN]; 59 int dfn[MAXN]; 60 int value[MAXN << 1], ranking[MAXN << 1]; 61 int dfsord = 0; 62 void DFS_LCA (int root, int fa) { 63 father[root] = fa; 64 dfn[root] = ++ dfsord; 65 value[dfsord] = deep[root], ranking[dfsord] = root; 66 for (int i = Head[root]; i; i = Link[i].next) { 67 int v = Link[i].to; 68 if (v == fa) 69 continue; 70 deep[v] = deep[root] + 1; 71 DFS_LCA (v, root); 72 value[++ dfsord] = deep[root], ranking[dfsord] = root; 73 } 74 } 75 pair<int, int> ST[MAXN << 1][20]; 76 void RMQ () { 77 for (int i = 1; i <= dfsord; i ++) 78 ST[i][0] = make_pair (value[i], ranking[i]); 79 for (int j = 1; j <= 18; j ++) 80 for (int i = 1; i + (1 << j) - 1 <= dfsord; i ++) 81 ST[i][j] = ST[i][j - 1].first < ST[i + (1 << (j - 1))][j - 1].first ? ST[i][j - 1] : ST[i + (1 << (j - 1))][j - 1]; 82 } 83 int LCA (int x, int y) { 84 int L = dfn[x], R = dfn[y]; 85 if (L > R) 86 swap (L, R); 87 int k = log2 (R - L + 1); 88 return ST[L][k].first < ST[R - (1 << k) + 1][k].first ? ST[L][k].second : ST[R - (1 << k) + 1][k].second; 89 } 90 91 LL ans = 0; 92 93 struct QuerySt { 94 int index; 95 int time; 96 int x, y; 97 98 QuerySt (int find = 0, int ftime = 0, int fx = 0, int fy = 0) : 99 index (find), time (ftime), x (fx), y (fy) {} 100 101 bool operator < (const QuerySt& p) const { 102 if (belong[x] != belong[p.x]) 103 return belong[x] < belong[p.x]; 104 if (belong[y] != belong[p.y]) 105 return belong[y] < belong[p.y]; 106 return time < p.time; 107 } 108 } ; 109 QuerySt Query[MAXQ]; 110 int qind = 0; 111 int modposi[MAXQ], modtime[MAXQ]; 112 int modpre[MAXQ], modval[MAXQ]; 113 int mind = 0, cur = 0; 114 int state[MAXN]= {0}; 115 int donet[MAXN]= {0}; 116 void reverse (int p) { 117 if (state[p]) 118 ans -= V[pcol[p]] * W[donet[pcol[p]]], donet[pcol[p]] --; 119 state[p] ^= 1; 120 if (state[p]) 121 donet[pcol[p]] ++, ans += V[pcol[p]] * W[donet[pcol[p]]]; 122 } 123 void move (int u, int v) { 124 int lca = LCA (u, v); 125 while (u != lca) 126 reverse (u), u = father[u]; 127 while (v != lca) 128 reverse (v), v = father[v]; 129 } 130 void extime (int p, int type) { 131 bool exist = false; 132 if (state[modposi[p]]) { 133 exist = true; 134 reverse (modposi[p]); 135 } 136 if (type == 1) { 137 modpre[p] = pcol[modposi[p]]; 138 pcol[modposi[p]] = modval[p]; 139 } 140 else { 141 pcol[modposi[p]] = modpre[p]; 142 } 143 if (exist) 144 reverse (modposi[p]); 145 } 146 void timemod (int ptime) { 147 while (cur < mind && modtime[cur + 1] <= ptime) 148 extime (++ cur, 1); 149 while (cur > 0 && modtime[cur] > ptime) 150 extime (cur --, 2); 151 } 152 LL answer[MAXQ]= {0}; 153 void Moqueue () { 154 int px = 1, py = 1; 155 for (int i = 1; i <= qind; i ++) { 156 int ind = Query[i].index, time = Query[i].time; 157 int x = Query[i].x, y = Query[i].y; 158 timemod (time); 159 move (px, x), px = x; 160 move (py, y), py = y; 161 int lca = LCA (px, py); 162 reverse (lca); 163 answer[ind] = ans; 164 reverse (lca); 165 } 166 } 167 168 int getnum () { 169 int num = 0; 170 char ch = getchar (); 171 172 while (! isdigit (ch)) 173 ch = getchar (); 174 while (isdigit (ch)) 175 num = (num << 3) + (num << 1) + ch - '0', ch = getchar (); 176 177 return num; 178 } 179 180 int main () { 181 N = getnum (), M = getnum (), Q = getnum (); 182 limit = (int) ceil (pow ((double) N, 2.0 / 3.0)); 183 for (int i = 1; i <= M; i ++) 184 V[i] = (LL) getnum (); 185 for (int i = 1; i <= N; i ++) 186 W[i] = (LL) getnum (); 187 for (int i = 1; i < N; i ++) { 188 int u = getnum (), v = getnum (); 189 Insert (u, v), Insert (v, u); 190 } 191 for (int i = 1; i <= N; i ++) 192 pcol[i] = getnum (); 193 DFS_bel (1, 0); 194 while (top > 0) 195 belong[Stack[top --]] = lind; 196 DFS_LCA (1, 0), RMQ (); 197 for (int i = 1; i <= Q; i ++) { 198 int opt = getnum (); 199 if (opt == 0) { 200 int p = getnum (), col = getnum (); 201 modposi[++ mind] = p, modtime[mind] = i, modval[mind] = col; 202 } 203 else if (opt == 1) { 204 int x = getnum (), y = getnum (); 205 qind ++, Query[qind] = (QuerySt (qind, i, x, y)); 206 } 207 } 208 sort (Query + 1, Query + qind + 1); 209 Moqueue (); 210 for (int i = 1; i <= qind; i ++) 211 printf ("%lld ", answer[i]); 212 213 return 0; 214 } 215 216 /* 217 4 3 5 218 1 9 2 219 7 6 5 1 220 2 3 221 3 1 222 3 4 223 1 2 3 2 224 1 1 2 225 1 4 2 226 0 2 1 227 1 1 2 228 1 4 2 229 */