重链剖分模板求调教!(码风良好)

P3384 【模板】重链剖分/树链剖分

玄关
by Lightning_Creeper @ 2023-08-20 16:41:56


在调了,等会。
by _HyperV_ @ 2023-08-20 16:43:28


浅改了一下,有什么不懂的可以来问。 强烈建议您阅读 **OI Wiki** 上的 [树链剖分](https://oi.wiki/graph/hld/) 页面 ```cpp #include <bits/stdc++.h> #define int long long using namespace std; const int MAXN = 1e5+5; int n, m, r; int p; struct Node { int l, r; int lz, sum; } tr[MAXN * 4]; int v[MAXN]; vector<int> G[MAXN]; int fa[MAXN], dep[MAXN], siz[MAXN], son[MAXN], top[MAXN], dfn[MAXN], val[MAXN], num; void lazy(int k, int v) { if (!v) return; tr[k].lz += v; tr[k].lz %= p; tr[k].sum = (tr[k].sum + 1LL * v % p * (tr[k].r - tr[k].l + 1) % p) % p; } void pushup(int k) { tr[k].sum = (tr[k * 2].sum + tr[k * 2 + 1].sum) % p; } void pushdown(int k) { lazy(k * 2, tr[k].lz); lazy(k * 2 + 1, tr[k].lz); tr[k].lz = 0; } void build(int k, int l, int r) { tr[k].l = l, tr[k].r = r; if (l == r) { tr[k].sum = val[l]; return; } int md = l + r >> 1; build(k * 2, l, md); build(k * 2 + 1, md + 1, r); pushup(k); } void update(int k, int l, int r, int v) { if (tr[k].r < l || r < tr[k].l) return; if (tr[k].l >= l && tr[k].r <= r) return lazy(k, v); pushdown(k); int lc = k * 2, rc = lc + 1; update(lc, l, r, v); update(rc, l, r, v); pushup(k); } int query(int k, int l, int r) { if (tr[k].r < l || r < tr[k].l) return 0; if (tr[k].l >= l && tr[k].r <= r) return tr[k].sum; pushdown(k); int lc = k * 2, rc = lc + 1; return (query(lc, l, r) + query(rc, l, r)) % p; } void dfs1(int u,int f) { siz[u] = 1, dep[u] = dep[fa[u] = f] + 1; for (int v : G[u]) { if (v == fa[u]) continue; dfs1(v, u); siz[u] += siz[v]; if (siz[v] > siz[son[u]]) son[u] = v; } } void dfs2(int u, int t) { // cerr << u << " " << t<< '\n'; top[u] = t; dfn[u] = ++num; val[num] = v[u]; if (!son[u]) return; dfs2(son[u], t); for (int v : G[u]) if (v != son[u] && v != fa[u]) dfs2(v, v); } void update_path(int x, int y, int z) { while (top[x] != top[y]) { if (dep[top[x]] < dep[top[y]]) swap(x, y); update(1, dfn[top[x]], dfn[x], z); x = fa[top[x]]; } if(dep[x] > dep[y]) swap(x, y); update(1, dfn[x], dfn[y], z); } int query_path(int x, int y) { int res = 0; while (top[x] != top[y]) { //cerr <<x << " "<<y<<'\n'; //cerr <<top[x]<<" " << top[y] << '\n'; if (dep[top[x]] < dep[top[y]]) swap(x, y); res = (res + query(1, dfn[top[x]], dfn[x])) % p; x = fa[top[x]]; } if (dep[x] > dep[y]) swap(x, y); res = (res + query(1, dfn[x], dfn[y])) % p; return res; } void update_tree(int x, int z) { update(1, dfn[x], dfn[x] + siz[x] - 1, z); } int query_tree(int x) { return query(1, dfn[x], dfn[x] + siz[x] - 1); } signed main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin >> n >> m >> r >> p; for (int i = 1; i <= n; i++) { cin >> v[i]; v[i] %= p; } for (int i = 1; i <= n - 1; i++) { int x, y; cin >> x >> y; G[x].push_back(y); G[y].push_back(x); } dfs1(r, 0); dfs2(r, r); build(1, 1, n); for (int i = 1; i <= m; i++) { // cerr << "fuck\n"; int opt, x, y; int z; cin >> opt; switch (opt) { case 1: cin >> x >> y >> z; update_path(x, y, z); break; case 2: cin >> x >> y; cout << query_path(x, y) << endl; break; case 3: cin >> x >> z; update_tree(x, z); break; case 4: cin >> x; cout << query_tree(x) << endl; break; } } return 0; } ```
by _HyperV_ @ 2023-08-20 18:19:13


@[Lightning_Creeper](/user/386547)
by _HyperV_ @ 2023-08-20 18:19:34


我的 `update_path` 和 `query_path` 就是照着 $\text{OIwiki}$ 写的。
by Lightning_Creeper @ 2023-08-21 08:59:00


|