算法学习-树链剖分

概述

树链剖分用于将树分割成若干条链的形式,以维护树上路径的信息。

具体来说,将整棵树剖分为若干条链,使它组合成线性结构,然后用其他的数据结构维护信息。

模板

【实现过程】

  1. 第一个 DFS 记录每个结点的深度(deep)、子树大小(size)。

  2. 第二个 DFS 记录每个结点的重子结点(heavy-son)、重边优先遍历时的 DFN 序、所在链的链顶(top,且应初始化为结点本身)。

  3. 链上的 DFN 序是连续的,可以使用线段树,树状数组维护。

    每次选择深度较大的链往上跳,直到两点在同一条链上。

  4. 在 DFS 搜索的时候,子树中的结点的 DFN 序是连续的。

    每一个结点记录 bottom 表示所在子树连续区间末端的结点。

    这样就把子树信息转化为连续的一段区间信息。

【代码】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
vector<int> G[MAXN];
int N, M, R, P;
int w[MAXN], fa[MAXN], size[MAXN], son[MAXN], top[MAXN], dep[MAXN];
int dfn[MAXN], dfn_index;
struct Node {
int l, r, sum, tag;
}node[MAXN * 2];
int cnt;
int a[MAXN];
inline void build(Node& u, int l, int r) {
u.tag = 0;
if (l == r) {
u.sum = a[l];
return;
}
int mid = (l + r) >> 1;
build(node[u.l = ++cnt], l, mid);
build(node[u.r = ++cnt], mid + 1, r);
u.sum = (node[u.l].sum + node[u.r].sum);
}
inline void pushdown(Node& u, int l, int r) {
if (u.tag) {
int mid = (l + r) >> 1;
node[u.l].sum = (node[u.l].sum + u.tag * (mid - l + 1));
node[u.r].sum = (node[u.r].sum + u.tag * (r - mid));
node[u.l].tag = (node[u.l].tag + u.tag);
node[u.r].tag = (node[u.r].tag + u.tag);
u.tag = 0;
}
}
inline void modify(Node& u, int l, int r, int ql, int qr, int val) {
if (ql <= l && r <= qr) {
u.tag = (u.tag + val) % P;
u.sum = (u.sum + val * (r - l + 1)) % P;
return;
}
pushdown(u, l, r);
int mid = (l + r) >> 1;
if (ql <= mid) modify(node[u.l], l, mid, ql, qr, val);
if (mid < qr) modify(node[u.r], mid + 1, r, ql, qr, val);
u.sum = (node[u.l].sum + node[u.r].sum) % P;
}
inline int query(Node& u, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) {
return u.sum;
}
int mid = (l + r) >> 1, ans = 0;
pushdown(u, l, r);
if (ql <= mid) ans = (ans + query(node[u.l], l, mid, ql, qr)) % P;
if (mid < qr) ans = (ans + query(node[u.r], mid + 1, r, ql, qr)) % P;
return ans;
}
inline void dfs1(int u, int fath) {
size[u] = 1;
fa[u] = fath;
dep[u] = dep[fath] + 1;
for (vector<int>::iterator it = G[u].begin(); it != G[u].end(); it++) {
int v = *it;
if (v == fath) continue;
dfs1(v, u);
size[u] += size[v];
if (size[v] > size[son[u]]) son[u] = v;
}
}
inline void dfs2(int u, int topc) {
top[u] = topc;
dfn[u] = ++dfn_index;
a[dfn[u]] = w[u];
if (son[u] == 0) return;
dfs2(son[u], topc);
for (vector<int>::iterator it = G[u].begin(); it != G[u].end(); it++) {
int v = *it;
if (v == fa[u] || v == son[u]) continue;
dfs2(v, v);
}
}
inline void ModifySubtree(int u, int val) {
modify(node[0], 1, N, dfn[u], dfn[u] + size[u] - 1, val);
}
inline int QuerySubtree(int u) {
return query(node[0], 1, N, dfn[u], dfn[u] + size[u] - 1);
}
inline void ModifyChain(int u, int v, int val) {
val %= P;
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) swap(u, v);
modify(node[0], 1, N, dfn[top[u]], dfn[u], val);
u = fa[top[u]];
}
if (dep[u] < dep[v]) swap(u, v);
modify(node[0], 1, N, dfn[v], dfn[u], val);
}
inline int QueryChain(int u, int v) {
int ans = 0;
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) swap(u, v);
ans = (ans + query(node[0], 1, N, dfn[top[u]], dfn[u])) % P;
u = fa[top[u]];
}
if (dep[u] < dep[v]) swap(u, v);
ans = (ans + query(node[0], 1, N, dfn[v], dfn[u])) % P;
return ans;
}
int main() {
scanf("%d%d%d%d", &N, &M, &R, &P);
for (register int i = 1; i <= N; ++i)
scanf("%d", &w[i]);
for (register int i = 1; i < N; ++i) {
int u, v;
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs1(R, 0);
dfs2(R, R);
build(node[0], 1, N);
for (register int i = 1; i <= M; ++i) {
int opt, x, y, z;
scanf("%d", &opt);
if (opt == 1) {
scanf("%d%d%d", &x, &y, &z);
ModifyChain(x, y, z);
}
if (opt == 2) {
scanf("%d%d", &x, &y);
printf("%d\n", QueryChain(x, y));
}
if (opt == 3) {
scanf("%d%d", &x, &z);
ModifySubtree(x, z);
}
if (opt == 4) {
scanf("%d", &x);
printf("%d\n", QuerySubtree(x));
}
}
return 0;
}

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×