长链剖分
因为重链剖分叫重女儿所以长链剖分叫长女儿。 参考资料。
O(nlogn)-O(1)求k级祖先,O(logn)求lca(也就是二分答案之后求k级祖先判定...)。
O(n)统计以深度为下标的信息。
性质1,总链长是O(n)数量级的。
写法跟树剖类似。
应用1:求k级祖先。
此处需要性质2:k级祖先所在长链,链长大于k。
预处理出每个链头上下长度为链长的信息。
值得注意的地方:len如果是最深深度,链长就是len - d。
母亲的d比女儿要小......经常写反。
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #include <vector> 5 6 const int N = 300010; 7 8 inline void read(int &x) { 9 x = 0; 10 char c = getchar(); 11 while(c < '0' || c > '9') c = getchar(); 12 while(c >= '0' && c <= '9') { 13 x = (x << 3) + (x << 1) + c - 48; 14 c = getchar(); 15 } 16 return; 17 } 18 19 struct Edge { 20 int nex, v; 21 }edge[N << 1]; int tp; 22 23 int e[N], n, father[N][20], son[N], len[N], d[N], top[N], pw[N]; 24 std::vector<int> fa[N], af[N]; 25 26 inline void add(int x, int y) { 27 tp++; 28 edge[tp].v = y; 29 edge[tp].nex = e[x]; 30 e[x] = tp; 31 return; 32 } 33 34 void DFS_1(int x, int f) { /// get d father son len 35 father[x][0] = f; 36 d[x] = d[f] + 1; 37 len[x] = d[x]; 38 for(int i = e[x]; i; i = edge[i].nex) { 39 int y = edge[i].v; 40 if(y == f) { 41 continue; 42 } 43 DFS_1(y, x); 44 len[x] = std::max(len[x], len[y]); 45 if(len[y] > len[son[x]]) { 46 son[x] = y; 47 } 48 } 49 return; 50 } 51 52 void DFS_2(int x, int f) { /// get top fa 53 top[x] = f; 54 if(son[x]) { 55 DFS_2(son[x], f); 56 } 57 for(int i = e[x]; i; i = edge[i].nex) { 58 int y = edge[i].v; 59 if(y == father[x][0] || y == son[x]) continue; 60 DFS_2(y, y); 61 } 62 return; 63 } 64 65 inline void prework() { 66 for(int i = 2; i <= n; i++) pw[i] = pw[i >> 1] + 1; 67 for(int j = 1; j <= pw[n]; j++) { 68 for(int i = 1; i <= n; i++) { 69 father[i][j] = father[father[i][j - 1]][j - 1]; 70 } 71 } 72 for(int x = 1; x <= n; x++) { 73 if(top[x] != x) continue; 74 int up = x, down = x; 75 for(int i = 0; i <= len[x] - d[x]; i++) { 76 fa[x].push_back(up); 77 af[x].push_back(down); 78 up = father[up][0]; 79 down = son[down]; 80 } 81 } 82 return; 83 } 84 85 inline int ask(int x, int k) { 86 if(!k) return x; 87 if(k >= d[x] || k < 0) return 0; 88 int t = pw[k]; 89 x = father[x][t]; 90 if(!x) return 0; 91 k -= (1 << t); 92 int y = top[x]; 93 if(d[x] - d[y] >= k) { 94 return af[y][d[x] - d[y] - k]; 95 } 96 return fa[y][k - d[x] + d[y]]; 97 } 98 99 int main() { 100 int m; 101 read(n); 102 for(int i = 1, x, y; i < n; i++) { 103 read(x); read(y); 104 add(x, y); add(y, x); 105 } 106 DFS_1(1, 0); 107 DFS_2(1, 1); 108 prework(); 109 read(m); 110 int lastans = 0; 111 for(int i = 1, x, y; i <= m; i++) { 112 read(x); read(y); 113 lastans = ask(x ^ lastans, y ^ lastans); 114 printf("%d\n", lastans); 115 } 116 return 0; 117 }
例题:BZOJ4381 Odwiedziny
对询问的步长根号分块。大于的暴力跳,小于的预处理出来,然后减去2 * lca即可。注意边界。(我居然1A了...写的check都没用到)
1 #include <bits/stdc++.h> 2 3 typedef long long LL; 4 const int N = 50010; 5 6 struct Edge { 7 int nex, v; 8 }edge[N << 1]; int tp; 9 10 int e[N], n, T, father[N][20], pw[N], b[N], c[N], d[N], len[N], top[N], son[N]; 11 std::vector<int> fa[N], af[N]; 12 LL val[N], Val[N][300]; 13 14 inline void add(int x, int y) { 15 tp++; 16 edge[tp].v = y; 17 edge[tp].nex = e[x]; 18 e[x] = tp; 19 return; 20 } 21 22 void DFS_1(int x, int f) { /// get father d len son 23 father[x][0] = f; 24 d[x] = d[f] + 1; 25 len[x] = d[x]; 26 for(int i = e[x]; i; i = edge[i].nex) { 27 int y = edge[i].v; 28 if(y == f) continue; 29 DFS_1(y, x); 30 len[x] = std::max(len[x], len[y]); 31 if(len[y] > len[son[x]]) { 32 son[x] = y; 33 } 34 } 35 return; 36 } 37 38 void DFS_2(int x, int f) { /// get top 39 top[x] = f; 40 if(son[x]) DFS_2(son[x], f); 41 for(int i = e[x]; i; i = edge[i].nex) { 42 int y = edge[i].v; 43 if(y == father[x][0] || y == son[x]) continue; 44 DFS_2(y, y); 45 } 46 return; 47 } 48 49 inline int getKfa(int x, int k) { 50 if(!k) return x; 51 if(k < 0 || k >= d[x]) return 0; 52 int t = pw[k]; 53 x = father[x][t]; 54 k -= (1 << t); 55 int y = top[x]; 56 if(k <= d[x] - d[y]) { 57 return af[y][d[x] - d[y] - k]; 58 } 59 return fa[y][k - d[x] + d[y]]; 60 } 61 62 void DFS_3(int x) { 63 int y = father[x][0]; 64 for(int i = 1; i <= T; i++) { 65 Val[x][i] = Val[y][i] + val[x]; 66 y = father[y][0]; 67 } 68 for(int i = e[x]; i; i = edge[i].nex) { 69 y = edge[i].v; 70 if(y == father[x][0]) continue; 71 DFS_3(y); 72 } 73 return; 74 } 75 76 inline void prework() { 77 for(int i = 2; i <= n; i++) pw[i] = pw[i >> 1] + 1; 78 for(int j = 1; j <= pw[n]; j++) { 79 for(int i = 1; i <= n; i++) { 80 father[i][j] = father[father[i][j - 1]][j - 1]; 81 } 82 } 83 for(int x = 1; x <= n; x++) { 84 if(top[x] != x) continue; 85 int up = x, down = x; 86 for(int i = 0; i <= len[x] - d[x]; i++) { 87 fa[x].push_back(up); 88 af[x].push_back(down); 89 up = father[up][0]; 90 down = son[down]; 91 } 92 } 93 DFS_3(1); 94 return; 95 } 96 97 inline void check() { 98 for(int x = 1; x <= n; x++) { 99 printf("x = %d top = %d len = %d d = %d \nfather : ", x, top[x], len[x], d[x]); 100 for(int i = 0; i <= pw[n]; i++) { 101 printf("%d ", father[x][i]); 102 } 103 printf("\nVal : "); 104 for(int i = 1; i <= T; i++) { 105 printf("%d ", Val[x][i]); 106 } 107 printf("\nKfa : "); 108 for(int i = 0; i <= d[x]; i++) { 109 printf("%d ", getKfa(x, i)); 110 } 111 printf("\n\n"); 112 } 113 return; 114 } 115 116 inline int lca(int x, int y) { 117 if(d[x] > d[y]) std::swap(x, y); 118 int t = pw[n]; 119 while(t >= 0 && d[x] < d[y]) { 120 if(d[father[y][t]] >= d[x]) { 121 y = father[y][t]; 122 } 123 t--; 124 } 125 if(x == y) return x; 126 t = pw[n]; 127 while(t >= 0 && father[x][0] != father[y][0]) { 128 if(father[x][t] != father[y][t]) { 129 x = father[x][t]; 130 y = father[y][t]; 131 } 132 t--; 133 } 134 return father[x][0]; 135 } 136 137 int main() { 138 scanf("%d", &n); 139 T = sqrt(n); 140 for(int i = 1; i <= n; i++) { 141 scanf("%d", &val[i]); 142 } 143 for(int i = 1, x, y; i < n; i++) { 144 scanf("%d%d", &x, &y); 145 add(x, y); add(y, x); 146 } 147 DFS_1(1, 0); 148 DFS_2(1, 1); 149 prework(); 150 151 for(int i = 1; i <= n; i++) scanf("%d", &b[i]); 152 for(int i = 1; i < n; i++) scanf("%d", &c[i]); 153 154 for(int i = 1; i < n; i++) { 155 int x = b[i], y = b[i + 1], z = lca(x, y); 156 int step = (d[x] + d[y] - 2 * d[z]) % c[i]; 157 LL ans = 0; 158 if(step) { 159 ans += val[y]; 160 y = getKfa(y, step); 161 } 162 if(c[i] > T) { /// bf 163 while(d[x] > d[z]) { 164 ans += val[x]; 165 x = getKfa(x, c[i]); 166 } 167 while(d[y] > d[z]) { 168 ans += val[y]; 169 y = getKfa(y, c[i]); 170 } 171 if(x == z) ans += val[z]; 172 } 173 else { 174 step = (d[x] - d[z]) % c[i]; 175 if(!step) ans -= val[z]; 176 int up = getKfa(x, ((d[x] - d[z]) / c[i] + 1) * c[i]); 177 ans += (Val[x][c[i]] - Val[up][c[i]]); 178 if(d[y] >= d[z]) { 179 up = getKfa(y, ((d[y] - d[z]) / c[i] + 1) * c[i]); 180 ans += (Val[y][c[i]] - Val[up][c[i]]); 181 } 182 } 183 printf("%lld\n", ans); 184 } 185 186 return 0; 187 }
应用2:统计信息。
关于内存分配:开一个N的数组就行了。把一条链上每个点的起始位置分配成连续的即可。注意不要越界了。
例题:CF1009F。注意合并的时候要更新答案。合并短女儿(?)链长的长度。
1 #include <bits/stdc++.h> 2 3 const int N = 2000010; 4 5 struct Edge { 6 int nex, v; 7 }edge[N << 1]; int tp; 8 9 int e[N], top[N], len[N], d[N], fa[N], son[N], n; 10 int f[N], op[N], num, ans[N]; 11 12 inline void add(int x, int y) { 13 tp++; 14 edge[tp].v = y; 15 edge[tp].nex = e[x]; 16 e[x] = tp; 17 return; 18 } 19 20 void DFS_1(int x, int f) { 21 fa[x] = f; 22 d[x] = d[f] + 1; 23 len[x] = d[x]; 24 for(int i = e[x]; i; i = edge[i].nex) { 25 int y = edge[i].v; 26 if(y == f) { 27 continue; 28 } 29 DFS_1(y, x); 30 len[x] = std::max(len[x], len[y]); 31 if(len[y] > len[son[x]]) { 32 son[x] = y; 33 } 34 } 35 return; 36 } 37 38 void DFS_2(int x, int f) { 39 top[x] = f; 40 op[x] = ++num; 41 if(son[x]) DFS_2(son[x], f); 42 for(int i = e[x]; i; i = edge[i].nex) { 43 int y = edge[i].v; 44 if(y == fa[x] || y == son[x]) continue; 45 DFS_2(y, y); 46 } 47 return; 48 } 49 50 void update(int x, int y) { 51 if(f[op[x] + ans[x]] < f[op[x] + ans[y] + 1]) { 52 ans[x] = ans[y] + 1; 53 } 54 else if(f[op[x] + ans[x]] == f[op[x] + ans[y] + 1]) { 55 ans[x] = std::min(ans[x], ans[y] + 1); 56 } 57 return; 58 } 59 60 void DFS(int x) { /// DP 61 f[op[x]]++; 62 ans[x] = 0; 63 if(son[x]) { 64 DFS(son[x]); 65 update(x, son[x]); 66 } 67 for(int i = e[x]; i; i = edge[i].nex) { 68 int y = edge[i].v; 69 if(y == fa[x] || y == son[x]) continue; 70 DFS(y); 71 for(int j = 0; j <= len[y] - d[y]; j++) { 72 f[op[x] + j + 1] += f[op[y] + j]; 73 if(f[op[x] + j + 1] > f[op[x] + ans[x]]) { 74 ans[x] = j + 1; 75 } 76 else if(f[op[x] + j + 1] == f[op[x] + ans[x]]) { 77 ans[x] = std::min(ans[x], j + 1); 78 } 79 } 80 update(x, y); 81 } 82 return; 83 } 84 85 int main() { 86 scanf("%d", &n); 87 for(int i = 1, x, y; i < n; i++) { 88 scanf("%d%d", &x, &y); 89 add(x, y); add(y, x); 90 } 91 DFS_1(1, 0); 92 DFS_2(1, 1); 93 DFS(1); 94 for(int i = 1; i <= n; i++) printf("%d\n", ans[i]); 95 return 0; 96 }
还可以OSU on tree来做。
BZOJ3252: 攻略
正解是DFS序,不过有个长链剖分的蛇皮怪做法.....首先转化成k个不相交的竖链。
本质都是贪心的取链删链。可以用DFS序维护每个点的收益,删链的时候暴力跳,每个点只会被跳到一次。
长链剖分就直接选链长前k大即可......
1 #include <bits/stdc++.h> 2 3 typedef long long LL; 4 const int N = 200010; 5 6 struct Edge { 7 int nex, v; 8 }edge[N << 1]; int tp; 9 10 int top[N], son[N], fa[N], e[N]; 11 LL val[N], d[N], len[N]; 12 std::priority_queue<LL> Q; 13 14 inline void add(int x, int y) { 15 tp++; 16 edge[tp].v = y; 17 edge[tp].nex = e[x]; 18 e[x] = tp; 19 return; 20 } 21 22 void DFS_1(int x, int f) { 23 len[x] = d[x]; 24 fa[x] = f; 25 for(int i = e[x]; i; i = edge[i].nex) { 26 int y = edge[i].v; 27 if(y == f) continue; 28 d[y] = d[x] + val[y]; 29 DFS_1(y, x); 30 len[x] = std::max(len[x], len[y]); 31 if(len[y] > len[son[x]]) { 32 son[x] = y; 33 } 34 } 35 return; 36 } 37 38 void DFS_2(int x, int f) { 39 top[x] = f; 40 if(son[x]) DFS_2(son[x], f); 41 for(int i = e[x]; i; i = edge[i].nex) { 42 int y = edge[i].v; 43 if(y == fa[x] || y == son[x]) continue; 44 DFS_2(y, y); 45 } 46 return; 47 } 48 49 int main() { 50 int n, k; 51 scanf("%d%d", &n, &k); 52 for(int i = 1; i <= n; i++) scanf("%lld", &val[i]); 53 for(int i = 1, x, y; i < n; i++) { 54 scanf("%d%d", &x, &y); 55 add(x, y); add(y, x); 56 } 57 58 d[1] = val[1]; 59 DFS_1(1, 0); 60 DFS_2(1, 1); 61 62 for(int x = 1; x <= n; x++) { 63 if(top[x] == x) Q.push(len[x] - d[fa[x]]); 64 } 65 LL ans = 0; 66 for(int i = 1; i <= k; i++) { 67 if(!Q.size()) break; 68 ans += Q.top(); 69 Q.pop(); 70 } 71 72 printf("%lld\n", ans); 73 return 0; 74 }
BZOJ3522: Hotel
这是水水版,但是n2DP居然卡我空间...转移顺序很毒,要memcpy。
1 #include <bits/stdc++.h> 2 3 #define forson(x, i) for(int i = e[x]; i; i = edge[i].nex) 4 #define rep(i, a, b) for(int i = a; i <= b; i++) 5 6 typedef long long LL; 7 const int N = 5010; 8 9 struct Edge { 10 int nex, v; 11 }edge[N << 1]; int tp; 12 13 int e[N], d[N], len[N]; 14 int f[N][N], g[N][N], t1[N], t2[N]; 15 LL ans; 16 17 inline void add(int x, int y) { 18 tp++; 19 edge[tp].v = y; 20 edge[tp].nex = e[x]; 21 e[x] = tp; 22 return; 23 } 24 25 void DFS(int x, int fa) { 26 d[x] = d[fa] + 1; 27 f[x][0] = 1; 28 len[x] = d[x]; 29 forson(x, i) { 30 int y = edge[i].v; 31 if(y == fa) continue; 32 DFS(y, x); 33 len[x] = std::max(len[x], len[y]); 34 /// DP ???? 35 memcpy(t1, f[x], sizeof(f[x])); 36 memcpy(t2, g[x], sizeof(g[x])); 37 for(int j = len[y] - d[y]; j >= 0; j--) { 38 ans += t1[j] * g[y][j + 1]; 39 ans += t2[j + 1] * f[y][j]; 40 //printf("ans += %lld * %lld \n", t1[j], g[y][j + 1]); 41 //printf("ans += %lld * %lld \n", t2[j + 1], f[y][j]); 42 //printf("ans = %lld \n", ans); 43 g[x][j + 1] += f[y][j] * t1[j + 1]; /// merge f -> g 44 f[x][j + 1] += f[y][j]; /// f -> f 45 g[x][j] += g[y][j + 1]; /// g -> g 46 } 47 /*printf("x = %d y = %d \n", x, y); 48 rep(j, 0, len[x]) { 49 printf("%d f %lld g %lld \n", j, f[x][j], g[x][j]); 50 } 51 puts("");*/ 52 } 53 return; 54 } 55 56 int main() { 57 //freopen("in.in", "r", stdin); 58 //freopen("my.out", "w", stdout); 59 60 //printf("%d \n", sizeof(f) * 2 / 1048576); 61 int n; 62 scanf("%d", &n); 63 rep(i, 1, n - 1) { 64 int x, y; 65 scanf("%d%d", &x, &y); 66 add(x, y); add(y, x); 67 } 68 DFS(1, 0); 69 printf("%lld\n", ans); 70 return 0; 71 }
有一种做法是枚举中间点。
用指针实现的长链剖分。注意这个倒着的g数组空间不好精确开......多开点就完事了。
1 #include <bits/stdc++.h> 2 3 #define forson(x, i) for(int i = e[x]; i; i = edge[i].nex) 4 5 typedef long long LL; 6 const int N = 200010; 7 8 struct Edge { 9 int nex, v; 10 }edge[N << 1]; int tp; 11 12 int e[N], d[N], len[N], fa[N], numf, numg, son[N], top[N], lm[N]; 13 LL F[N << 1], G[N << 2], *f[N], *g[N]; 14 LL ans; 15 16 inline void add(int x, int y) { 17 tp++; 18 edge[tp].v = y; 19 edge[tp].nex = e[x]; 20 e[x] = tp; 21 return; 22 } 23 24 /* the old DFS ELF ELF elf Asphodelus minori August yuzu-soft KID Key Leaf aquasoft kenoQ ASPHODELUS Restoration Hesitation Snow Moving Go On AlphaBeta Distrily Island 25 void DFS(int x, int fa) { 26 d[x] = d[fa] + 1; 27 f[x][0] = 1; 28 len[x] = d[x]; 29 forson(x, i) { 30 int y = edge[i].v; 31 if(y == fa) continue; 32 DFS(y, x); 33 len[x] = std::max(len[x], len[y]); 34 /// DP ???? 35 memcpy(t1, f[x], sizeof(f[x])); 36 memcpy(t2, g[x], sizeof(g[x])); 37 for(int j = len[y] - d[y]; j >= 0; j--) { 38 ans += t1[j] * g[y][j + 1]; 39 ans += t2[j + 1] * f[y][j]; 40 g[x][j + 1] += f[y][j] * t1[j + 1]; /// merge f -> g 41 f[x][j + 1] += f[y][j]; /// f -> f 42 g[x][j] += g[y][j + 1]; /// g -> g 43 } 44 } 45 return; 46 } 47 */ 48 49 void DFS_1(int x, int father) { 50 d[x] = d[father] + 1; 51 fa[x] = father; 52 len[x] = d[x]; 53 forson(x, i) { 54 int y = edge[i].v; 55 if(y == father) continue; 56 DFS_1(y, x); 57 len[x] = std::max(len[x], len[y]); 58 if(len[y] > len[son[x]]) { 59 son[x] = y; 60 } 61 } 62 lm[x] = len[x] - d[x]; 63 return; 64 } 65 66 void DFS_2(int x, int father) { 67 top[x] = father; 68 f[x] = F + (++numf); 69 g[x] = G + (++numg); 70 //g[x] = G + numf; 71 if(son[x]) { 72 DFS_2(son[x], father); 73 } 74 forson(x, i) { 75 int y = edge[i].v; 76 if(y == fa[x] || y == son[x]) continue; 77 numg += lm[y]; 78 DFS_2(y, y); 79 } 80 81 return; 82 } 83 84 inline void out(int x) { 85 for(int i = 0; i <= len[x] - d[x]; i++) { 86 printf("f %d %d = %d \n", x, i, f[x][i]); 87 } 88 for(int i = 0; i <= lm[x]; i++) { 89 printf("g %d %d = %d \n", x, i, g[x][-i]); 90 } 91 return; 92 } 93 94 void DFS(int x) { 95 f[x][0] = 1; 96 if(son[x]) DFS(son[x]); 97 ans += g[x][0]; 98 99 //printf("%d -- > %d \n", x, son[x]); 100 //out(x); 101 102 forson(x, i) { 103 int y = edge[i].v; 104 if(y == fa[x] || y == son[x]) continue; 105 DFS(y); 106 /// merge 107 for(int i = 0; i <= len[x] - d[x] && i < lm[y]; i++) { 108 ans += f[x][i] * g[y][-(i + 1)]; 109 } 110 for(int i = 0; i <= len[y] - d[y] && i < lm[x]; i++) { 111 ans += g[x][-(i + 1)] * f[y][i]; 112 } 113 for(int i = 0; i <= len[y] - d[y] && i < lm[x] && i < len[x] - d[x]; i++) { 114 g[x][-(i + 1)] += f[x][i + 1] * f[y][i]; /// i < d[x] 115 //if(x == 5 && i + 1 == 2) printf("1111111111111111111"); 116 } 117 for(int i = 0; i <= lm[x] && i < lm[y]; i++) { 118 g[x][-(i)] += g[y][-(i + 1)]; /// i < d[x] 119 //if(x == 5 && i == 2) printf("g %d %d = %lld \n", x, i, g[x][-i]); 120 //if(x == 5 && i == 2) printf("222222222222222"); 121 } 122 for(int i = 0; i <= len[y] - d[y] && i < len[x] - d[x]; i++) { 123 f[x][i + 1] += f[y][i]; /// 124 } 125 126 //printf("%d -> %d \n", x, y); 127 //out(x); 128 } 129 return; 130 } 131 132 int main() { 133 134 int n; 135 scanf("%d", &n); 136 for(int i = 1; i < n; i++) { 137 int x, y; 138 scanf("%d%d", &x, &y); 139 add(x, y); add(y, x); 140 } 141 DFS_1(1, 0); 142 numg = N; 143 DFS_2(1, 1); 144 DFS(1); 145 printf("%lld\n", ans); 146 return 0; 147 }