BZOJ 3786
给一棵n个点的点带权的树,有m次操作,操作分三种,询问点到根的路径点权和,子树加,换父亲。
$$n \leq 1\times 10^5,m \leq 3\times 10^5$$
先想LCT,但没办法子树加,所以可以维护进出栈序,这样操作一就是前缀和,操作二就是区间加,操作三就是区间平移,用splay维护即可。
const int MAXN = 100000 + 5; struct Input { char buf[1 << 25], *s; Input() { #ifdef LOCAL freopen("BZOJ3786.in", "r", stdin); freopen("BZOJ3786.out", "w", stdout); #endif fread(s = buf, 1, 1 << 25, stdin); } friend Input &operator>>(Input &io, int &x) { x = 0; while (!isdigit(*io.s)) ++ io.s; while (isdigit(*io.s)) x = x * 10 + *io.s ++ - '0'; return io; } friend Input &operator>>(Input &io, char *s) { while (isspace(*io.s)) ++ io.s; while (!isspace(*io.s)) *s ++ = *io.s ++; return io; } } cin; int arr[MAXN * 2]; bool ok[MAXN * 2]; struct Splay { struct Node { Node *fa, *ch[2]; int sz, val, addv; bool ok; LL sum; Node() {} Node(Node *p, int v, bool o) : fa(p), sz(1), val(v), addv(0), ok(o), sum(v) { ch[0] = ch[1] = NULL; } bool relation() { return this == fa->ch[1]; } #define _sz(x) ((x) ? (x)->sz : 0) #define _sum(x) ((x) ? (x)->sum : 0) void push_up() { sz = _sz(ch[0]) + (ok ? 1 : -1) + _sz(ch[1]); sum = _sum(ch[0]) + val + _sum(ch[1]); } void push_down() { if (addv) { FOR(i, 0, 2) if (ch[i]) { ch[i]->addv += addv; ch[i]->val += ch[i]->ok ? addv : -addv; ch[i]->sum += 1LL * addv * ch[i]->sz; } addv = 0; } } } *nd[MAXN * 2]; Node *build(Node *par, int l, int r) { if (l > r) return NULL; int mid = (l + r) >> 1; nd[mid] = new Node(par, arr[mid], ok[mid]); nd[mid]->ch[0] = build(nd[mid], l, mid - 1); nd[mid]->ch[1] = build(nd[mid], mid + 1, r); nd[mid]->push_up(); return nd[mid]; } void rotate(Node *o) { int t = o->relation(); Node *par = o->fa; par->ch[t] = o->ch[t ^ 1]; if (o->ch[t ^ 1]) o->ch[t ^ 1]->fa = par; if (par->fa) par->fa->ch[par->relation()] = o; o->fa = par->fa, o->ch[t ^ 1] = par, par->fa = o; par->push_up(); o->push_up(); } void splay(Node *o) { static Node *stk[MAXN * 2]; int top = 0; for (Node *tmp = o; tmp; tmp = tmp->fa) stk[++ top] = tmp; Rep(i, top, 1) stk[i]->push_down(); for (; o->fa; rotate(o)) if (o->fa->fa) rotate(o->fa->relation() == o->relation() ? o->fa : o); } Node *split(Node *o, int d) { splay(o); Node *p = o->ch[d]; if (p) p->fa = NULL; o->ch[d] = NULL; o->push_up(); return p; } Node *min(Node *o) { Node *k = o; for (; k->ch[0]; k = k->ch[0]); return k; } Node *max(Node *o) { Node *k = o; for (; k->ch[1]; k = k->ch[1]); return k; } void merge(Node *o, Node *p) { if (!o || !p) return; Node *q = max(o); splay(q); splay(p); q->ch[1] = p; p->fa = q; q->push_up(); } std::pair <Node *, Node *> select(Node *l, Node *r) { std::pair <Node *, Node *> res; res.F = split(l, 0), res.S = split(r, 1); return res; } LL query(Node *l, Node *r) { std::pair <Node *, Node *> tmp = select(l, r); splay(l); LL ans = l->sum; merge(tmp.F, l); merge(l, tmp.S); return ans; } void modify(Node *l, Node *r, int x) { std::pair <Node *, Node *> tmp = select(l, r); splay(l); l->addv += x; l->val += l->ok ? x : -x; l->sum += 1LL * l->sz * x; merge(tmp.F, l); merge(l, tmp.S); } void change(Node *l, Node *r, Node *target) { std::pair <Node *, Node *> tmp = select(l, r); merge(tmp.F, tmp.S); Node *c = split(target, 1); merge(target, l); merge(l, c); } } S; struct Tree { int hed[MAXN], nxt[MAXN * 2], to[MAXN * 2], val[MAXN], fa[MAXN], L[MAXN], R[MAXN], cnt, dfn; void add_edge(int u, int v) { ++ cnt; to[cnt] = v; nxt[cnt] = hed[u]; hed[u] = cnt; } void DFS(int u) { ++ dfn; arr[dfn] = val[u]; ok[dfn] = 1; L[u] = dfn; for (int e = hed[u]; e; e = nxt[e]) { int v = to[e]; if (v != fa[u]) { fa[v] = u; DFS(v); } } ++ dfn; arr[dfn] = -val[u]; ok[dfn] = 0; R[u] = dfn; } } T; int main() { int n; cin >> n; For(i, 2, n) { int par; cin >> par; T.add_edge(par, i); T.add_edge(i, par); } For(i, 1, n) cin >> T.val[i]; T.DFS(1); S.build(NULL, 1, n * 2); int m; cin >> m; For(i, 1, m) { static char opt[5]; cin >> opt; if (opt[0] == 'Q') { int d; cin >> d; printf("%lld\n", S.query(S.nd[1], S.nd[T.L[d]])); } else if (opt[0] == 'C') { int x, y; cin >> x >> y; S.change(S.nd[T.L[x]], S.nd[T.R[x]], S.nd[T.L[y]]); } else { int p, q; cin >> p >> q; S.modify(S.nd[T.L[p]], S.nd[T.R[p]], q); } } return 0; }