树链剖分//模板题
由于存在换根操作
对所有关于节点 u 的修改和查询操作进行分类讨论
若 Root 在 u 的子树中,则不处理 u 所在的 Root 的那颗子树
否则不会有影响
寻找 Root 所在的那颗子树的根可以用倍增求
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <string> const int N = 1e5 + 10; #define LL long long int topp[N], fa[N], size[N], son[N], deep[N], tree[N], lst[N], rst[N], bef[N], data[N]; int f[N][30]; int Tree; LL W[N << 2], F[N << 2], S[N << 2]; struct Node { int u, v, nxt; } G[N << 1]; int now, head[N]; int n, m, Root; int opt, T; #define gc getchar() inline int read() { int x = 0; char c = gc; while(c < '0' || c > '9') c = gc; while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc; return x; } void Add(int u, int v) {G[++ now].v = v; G[now].nxt = head[u]; head[u] = now;} void Dfs_1(int u, int f_, int dep) { fa[u] = f_, deep[u] = dep, size[u] = 1; for(int i = head[u]; ~ i; i = G[i].nxt) { int v = G[i].v; if(v == f_) continue; f[v][0] = u; Dfs_1(v, u, dep + 1); size[u] += size[v]; if(size[son[u]] < size[v]) son[u] = v; } } void Dfs_2(int u, int tp) { topp[u] = tp, tree[u] = ++ Tree, bef[Tree] = u, lst[u] = Tree; if(!son[u]) { rst[u] = Tree; return ; } Dfs_2(son[u], tp); for(int i = head[u]; ~ i; i = G[i].nxt) { int v = G[i].v; if(v != fa[u] && v != son[u]) Dfs_2(v, v); } rst[u] = Tree; } void Before() { for(int i = 1; (1 << i) <= n; i ++) for(int j = 1; j <= n; j ++) if(f[j][i - 1]) f[j][i] = f[f[j][i - 1]][i - 1]; } #define lson jd << 1 #define rson jd << 1 | 1 void Build_tree(int l, int r, int jd) { S[jd] = (r - l + 1); if(l == r) { W[jd] = data[bef[l]]; return ; } int mid = (l + r) >> 1; Build_tree(l, mid, lson); Build_tree(mid + 1, r, rson); W[jd] = W[lson] + W[rson]; } void Pushdown(int jd) { if(!F[jd]) return ; F[lson] += F[jd]; F[rson] += F[jd]; W[lson] += (S[lson] * F[jd]); W[rson] += (S[rson] * F[jd]); F[jd] = 0; } void Sec_G(int l, int r, int jd, int x, int y, int num) { if(x <= l && r <= y) { F[jd] += num; W[jd] += (S[jd] * num); return ; } Pushdown(jd); int mid = (l + r) >> 1; if(x <= mid) Sec_G(l, mid, lson, x, y, num); if(y > mid) Sec_G(mid + 1, r, rson, x, y, num); W[jd] = W[lson] + W[rson]; } void Sec_G_imp(int x, int y, int num) { int tpx = topp[x], tpy = topp[y]; while(tpx != tpy) { if(deep[tpx] < deep[tpy]) std:: swap(tpx, tpy), std:: swap(x, y); Sec_G(1, n, 1, tree[tpx], tree[x], num); x = fa[tpx]; tpx = topp[x]; } if(deep[x] < deep[y]) std:: swap(x, y); Sec_G(1, n, 1, tree[y], tree[x], num); return ; } inline int Find(int x, int y) { int dy = deep[y], dx = deep[x]; int del = deep[y] - deep[x] - 1; for(int i = 0; (1 << i) <= del; i ++) if(del & (1 << i)) y = f[y][i]; return y; } LL Answer; void Sec_A(int l, int r, int jd, int x, int y) { if(x <= l && r <= y) { Answer += W[jd]; return ; } Pushdown(jd); int mid = (l + r) >> 1; if(x <= mid) Sec_A(l, mid, lson, x, y); if(y > mid) Sec_A(mid + 1, r, rson, x, y); } LL Sec_A_imp(int x, int y) { int tpx = topp[x], tpy = topp[y]; LL ret = 0; while(tpx != tpy) { if(deep[tpx] < deep[tpy]) std:: swap(tpx, tpy), std:: swap(x, y); Answer = 0; Sec_A(1, n, 1, tree[tpx], tree[x]); ret += Answer; x = fa[tpx]; tpx = topp[x]; } if(deep[x] < deep[y]) std:: swap(x, y); Answer = 0; Sec_A(1, n, 1, tree[y], tree[x]); ret += Answer; return ret; } int main() { Root = 1; n = read(); for(int i = 1; i <= n; i ++) head[i] = -1; for(int i = 1; i <= n; i ++) data[i] = read(); for(int i = 1; i < n; i ++) { int u = read(); Add(i + 1, u), Add(u, i + 1); } Dfs_1(1, 0, 1); Dfs_2(1, 1); Build_tree(1, n, 1); Before(); int t = read(); for(T = 1; T <= t; T ++) { opt = read(); if(opt == 1) Root = read(); else if(opt == 2) { int u = read(), v = read(), x = read(); Sec_G_imp(u, v, x); } else if(opt == 3) { int u = read(), x = read(); if(Root == u) { Sec_G(1, n, 1, 1, n, x); continue; } if(lst[u] <= tree[Root] && tree[Root] <= rst[u]) { Sec_G(1, n, 1, 1, n, x); int Use_son = Find(u, Root); Sec_G(1, n, 1, lst[Use_son], rst[Use_son], -x); } else Sec_G(1, n, 1, lst[u], rst[u], x); } else if(opt == 4) { int x = read(), y = read(); printf("%lld ", Sec_A_imp(x, y)); } else { int u = read(); if(Root == u) { Answer = 0; Sec_A(1, n, 1, 1, n); printf("%lld ", Answer); continue; } LL Now_ans = 0; if(lst[u] <= tree[Root] && tree[Root] <= rst[u]) { Answer = 0; Sec_A(1, n, 1, 1, n); Now_ans += Answer; int Use_son = Find(u, Root); Answer = 0; Sec_A(1, n, 1, lst[Use_son], rst[Use_son]); Now_ans -= Answer; } else { Answer = 0; Sec_A(1, n, 1, lst[u], rst[u]); Now_ans += Answer; } printf("%lld ", Now_ans); } } return 0; }