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 序连续,因此可以方便地用一些维护序列的数据结构(如线段树)来维护树上路径的信息。

 

如:

 

  1. 修改 树上两点之间的路径上 所有点的值。
  2. 查询 树上两点之间的路径上 节点权值的 和/极值/其它(在序列上可以用数据结构维护,便于合并的信息)

 

除了配合数据结构来维护树上路径信息,树剖还可以用来 (且常数较小)地求 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

 

 

 

 
 
posted @ 2022-08-04 18:40  Keyzee  阅读(34)  评论(0编辑  收藏  举报