P3384 【模板】轻重链剖分/树链剖分
题目传送门:https://www.luogu.com.cn/problem/P3384
详解可看:https://blog.csdn.net/a_forever_dream/article/details/80651308 /or/ https://oi-wiki.org/graph/hld/#_6
树链剖分用于将树分割成若干条链的形式,以维护树上路径的信息。
具体来说,将整棵树剖分为若干条链,使它组合成线性结构,然后用其他的数据结构维护信息。
重链剖分能保证划分出的每条链上的节点 DFS 序连续,因此可以方便地用一些维护序列的数据结构(如线段树)来维护树上路径的信息。
如:
- 修改 树上两点之间的路径上 所有点的值。
- 查询 树上两点之间的路径上 节点权值的 和/极值/其它(在序列上可以用数据结构维护,便于合并的信息)。
除了配合数据结构来维护树上路径信息,树剖还可以用来 (且常数较小)地求 LCA。在某些题目中,还可以利用其性质来灵活地运用树剖。
代码:我根据自己的代码风格,修改了一部分。
1 #include<iostream>
2 #include<cstdio>
3 #include<vector>
4 #include<map>
5 #include<queue>
6 #include<set>
7 #include<algorithm>
8 #include<stack>
9 #include<cmath>
10 #include<cstring>
11 #include<string>
12 using namespace std;
13 #define int long long
14 #define gc getchar()
15 #define rd(x) read(x)
16 #define el '\n'
17 #define rep(i, a, n) for(int i = (a); i <= n; ++i)
18 #define per(i, a, n) for(int i = (a); i >= n; --i)
19 using ll = long long;
20 using db = double;
21 using ldb = long double;
22 const int N = 500000 + 10;
23 const int mod = 1e9 + 7;
24 const int inf = 0x3f3f3f3f;
25
26 template <typename _T>
27 inline void read(_T & f) {
28 f = 0; _T fu = 1; char c = gc;
29 while (c < '0' || c > '9') { if (c == '-') { fu = -1; } c = gc; }
30 while (c >= '0' && c <= '9') { f = (f << 3) + (f << 1) + (c & 15); c = gc; }
31 f *= fu;
32 }
33
34 template <typename T>
35 void print(T x) {
36 if (x < 0) putchar('-'), x = -x;
37 if (x < 10) putchar(x + 48);
38 else print(x / 10), putchar(x % 10 + 48);
39 }
40
41 template <typename T>
42 void print(T x, char t) {
43 print(x); putchar(t);
44 }
45
46 struct node {
47 int to, w, next;
48 }e[N << 2];
49 int head[N << 2], tot;
50
51 void add(int u, int v) {
52 e[tot].to = v;
53 //e[tot].w = w;
54 e[tot].next = head[u];
55 head[u] = tot++;
56 }
57
58 int dep[N], fa[N], siz[N], son[N];
59
60 void dfs1(int x) {
61 siz[x] = 1;
62 for (int i = head[x]; i + 1; i = e[i].next) {
63 int to = e[i].to;
64 if (to == fa[x]) continue;
65 dep[to] = dep[x] + 1;
66 fa[to] = x;
67 dfs1(to);
68 siz[x] += siz[to];
69 if (siz[to] > siz[son[x]]) son[x] = to;
70 }
71 }
72
73 int top[N], rnk[N], ctr[N], dfn[N], cnt;
74
75 void dfs2(int x, int tp) {
76 top[x] = tp;
77 dfn[x] = ++cnt;
78 rnk[cnt] = x;
79 if (son[x]) dfs2(son[x], tp);
80 for (int i = head[x]; i + 1; i = e[i].next) {
81 int to = e[i].to;
82 if (to != son[x] && to != fa[x]) dfs2(to, to);
83 }
84 ctr[x] = cnt;
85 }
86
87 int w[N], p;
88 int n, m, root;
89
90 struct SegTree {
91 int sum[N << 4], lazy[N << 4];
92 void PushUp(int rt) {
93 sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
94 }
95 void Build(int l, int r, int rt) {
96 if (l == r) {
97 sum[rt] = w[rnk[l]];
98 return;
99 }
100 int m = (l + r) >> 1;
101 Build(l, m, rt << 1);
102 Build(m + 1, r, rt << 1 | 1);
103 PushUp(rt);
104 }
105 void PushDown(int rt, int ln, int rn) {
106 if (lazy[rt]) {
107 lazy[rt << 1] += lazy[rt];
108 lazy[rt << 1 | 1] += lazy[rt];
109 sum[rt << 1] += lazy[rt] * ln;
110 sum[rt << 1 | 1] += lazy[rt] * rn;
111 lazy[rt] = 0;
112 }
113 }
114 void Update(int L, int R, int C, int l, int r, int rt) {
115 if (l >= L && r <= R) {
116 sum[rt] += C * (r - l + 1);
117 lazy[rt] += C;
118 return;
119 }
120 int m = (l + r) >> 1;
121 PushDown(rt, m - l + 1, r - m);
122 if (m >= L) Update(L, R, C, l, m, rt << 1);
123 if (m < R) Update(L, R, C, m + 1, r, rt << 1 | 1);
124 PushUp(rt);
125 }
126 int Query(int L, int R, int l, int r, int rt) {
127 if (l >= L && r <= R) {
128 return sum[rt];
129 }
130 int m = (l + r) >> 1;
131 PushDown(rt, m - l + 1, r - m);
132 int ans = 0;
133 if(m >= L) ans = (ans + Query(L, R, l, m, rt << 1)) % p;
134 if(m < R) ans = (ans + Query(L, R, m + 1, r, rt << 1 | 1)) % p;
135 return ans % p;
136 }
137 }st;
138
139 void change_xtoy() {
140 int x, y, z;
141 cin >> x >> y >> z;
142 while (top[x] != top[y]) {
143 if (dep[top[x]] > dep[top[y]]) swap(x, y);
144 st.Update(dfn[top[y]], dfn[y], z, 1, cnt, 1);
145 y = fa[top[y]];
146 }
147 if (dep[x] > dep[y]) swap(x, y);
148 st.Update(dfn[x], dfn[y], z, 1, cnt, 1);
149 }
150
151 void getsum_xtoy() {
152 int x, y;
153 cin >> x >> y;
154 ll ans = 0;
155 while (top[x] != top[y]) {
156 if (dep[top[x]] > dep[top[y]]) swap(x, y);
157 ans = (ans + st.Query(dfn[top[y]], dfn[y], 1, cnt, 1)) % p;
158 y = fa[top[y]];
159 }
160 if (dep[x] > dep[y]) swap(x, y);
161 ans = (ans + st.Query(dfn[x], dfn[y], 1, cnt, 1)) % p;
162 cout << ans << "\n";
163 }
164
165 void change_sontree() {
166 int x, z;
167 cin >> x >> z;
168 st.Update(dfn[x], ctr[x], z, 1, cnt, 1);
169 }
170
171 void getsum_sontree() {
172 int x;
173 cin >> x;
174 cout << st.Query(dfn[x], ctr[x], 1, cnt, 1) << "\n";
175 }
176
177 signed main() {
178
179 ios::sync_with_stdio(false);
180 cin.tie(0), cout.tie(0);
181 cin >> n >> m >> root >> p;
182 memset(head, -1, sizeof(head));
183 tot = 0;
184 for (int i = 1; i <= n; i++) {
185 cin >> w[i];
186 }
187 for (int i = 1; i < n; i++) {
188 int u, v;
189 cin >> u >> v;
190 add(u, v);
191 add(v, u);
192 }
193 dfs1(root);
194 dfs2(root, root);
195 st.Build(1, cnt, 1);
196 for (; m; --m) {
197 int op;
198 cin >> op;
199 if (op == 1) change_xtoy();
200 if (op == 2) getsum_xtoy();
201 if (op == 3) change_sontree();
202 if (op == 4) getsum_sontree();
203 }
204
205 return 0;
206 }
207
208 //8 10 2 448348
209 //458 718 447 857 633 264 238 944
210 //1 2
211 //2 3
212 //3 4
213 //6 2
214 //1 5
215 //5 7
216 //8 6
217 //3 7 611
218 //4 6
219 //3 1 267
220 //3 2 111
221 //1 6 3 153
222 //3 7 673
223 //4 8
224 //2 6 1
225 //4 7
226 //3 4 228
永远热爱,永远向着光。