题意:
一颗有根树,支持询问点到根路径权值和,子树加,换父亲
欧拉序列怎么求路径权值和?
一个点的权值只会给自己的子树中的点贡献,入栈权值正出栈权值负,求前缀和就行了!
和上题一样,伪ETT大法好
注意本题的子树需要根,所以需要找到子树区间左右的前驱和后继节点把他们splay出来才能得到子树区间,不能直接$l-1, r+1$,一开始写错了
然后注意下放标记,splay需要记录splay子树里有几个入栈几个出栈
加强版:询问任意一条路径$(u,v)$
当然需要减去lca了,于是用一个LCT维护树的形态
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; #define lc t[x].ch[0] #define rc t[x].ch[1] #define pa t[x].fa #define pii pair<int, int> #define MP make_pair #define fir first #define sec second typedef long long ll; const int N=2e5+5; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();} return x*f; } int n, a[N], x, y, Q, fa[N]; char s[5]; struct edge{int v, ne;} e[N]; int cnt, h[N]; inline void ins(int u, int v) { e[++cnt]=(edge){v, h[u]}; h[u]=cnt; } pii dfn[N]; int dfc, eul[N]; void dfs(int u) { dfn[u].fir = ++dfc; eul[dfc] = u; for(int i=h[u]; i; i=e[i].ne) dfs(e[i].v); dfn[u].sec = ++dfc; eul[dfc] = -u; } struct meow{int ch[2], fa, v, sl, sr, type; ll sum, tag;} t[N]; int root, sz; inline int wh(int x) {return t[pa].ch[1] == x;} inline void update(int x) { t[x].sum = t[lc].sum + t[rc].sum + t[x].v; t[x].sl = t[lc].sl + t[rc].sl + (t[x].type==1); t[x].sr = t[lc].sr + t[rc].sr + (t[x].type==-1); } inline void paint(int x, int d) { t[x].sum += (ll)d*(t[x].sl - t[x].sr); t[x].v += d*t[x].type; t[x].tag += d; } inline void pushDown(int x) { //printf("pushDown %d ",x); if(t[x].tag) { //puts("yes"); if(lc) paint(lc, t[x].tag); if(rc) paint(rc, t[x].tag); t[x].tag = 0; } } void pd(int x) { if(pa) pd(pa); pushDown(x); } inline void rotate(int x) { int f=t[x].fa, g=t[f].fa, c=wh(x); if(g) t[g].ch[wh(f)] = x; t[x].fa=g; t[f].ch[c] = t[x].ch[c^1]; t[t[f].ch[c]].fa=f; t[x].ch[c^1] = f; t[f].fa=x; update(f); update(x); } inline void splay(int x, int tar) { pd(x); for(; pa!=tar; rotate(x)) if(t[pa].fa != tar) rotate(wh(x)==wh(pa) ? pa : x); if(tar==0) root=x; } void build(int &x, int l, int r, int f) { int mid = (l+r)>>1; x=mid; t[x].fa=f; if(eul[x]>0) t[x].type = 1, t[x].v = a[eul[x]]; else t[x].type = -1, t[x].v = -a[-eul[x]]; if(l<mid) build(lc, l, mid-1, x); if(mid<r) build(rc, mid+1, r, x); update(x); } inline int pre(int x) { x = lc; while(rc) x = rc; return x; } inline int nex(int x) { x = rc; while(lc) x = lc; return x; } inline void Split(int &p, int &x) { splay(p, 0); p = pre(p); splay(x, 0); x = nex(x); splay(p, 0); splay(x, p); } ll Que(int u) { int p = dfn[1].fir, x = dfn[u].fir; Split(p, x); return t[lc].sum; } void Cha(int u, int far) { int p = dfn[u].fir, x = dfn[u].sec; Split(p, x); int q = lc; lc = t[q].fa = 0; update(x); update(p); p = dfn[far].fir; splay(p, 0); x = nex(p); splay(x, p); lc = q; t[q].fa = x; update(x); update(p); } void AddVal(int u, int d) { int p = dfn[u].fir, x = dfn[u].sec; Split(p, x); paint(lc, d); } int main() { //freopen("in","r",stdin); freopen("galaxy.in", "r", stdin); freopen("galaxy.out", "w", stdout); n=read(); for(int i=2; i<=n; i++) ins(read(), i); for(int i=1; i<=n; i++) a[i]=read(); dfc=1; dfs(1); dfc++; build(root, 1, dfc, 0); Q=read(); for(int i=1; i<=Q; i++) { scanf("%s", s); x=read(); if(s[0]=='Q') printf("%lld ", Que(x)); else if(s[0]=='C') Cha(x, read()); else AddVal(x, read()); } }