长链剖分

因为重链剖分叫重女儿所以长链剖分叫长女儿。 参考资料

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 }
AC代码

例题: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 }
AC代码

应用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 }
AC代码

还可以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 }
AC代码

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 }
50分DP

有一种做法是枚举中间点。

用指针实现的长链剖分。注意这个倒着的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 }
AC代码

 

posted @ 2019-03-06 21:23  huyufeifei  阅读(271)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜