BZOJ3786 : 星系探索
由于没有换根操作,所以直接用Splay维护DFS括号序列即可。
对于查询1到x路径和,就是已入栈的减去已出栈的。
子树加相当于区间加。
换父亲相当于一个区间的移动。
本题非常卡常数,一开始直接扒3153的代码狂T不止,改写Splay后也是狂T不止,最后把Splay从数组储存改成结构体储存才AC。
#include<cstdio> #define N 200010 typedef long long ll; struct P{ int f,son[2],ci,co;ll val,tag,sum;bool is; P(){f=son[0]=son[1]=ci=co=val=tag=sum=is=0;} }T[N]; int n,m,i,x,y,root,a[N],g[N],nxt[N],v[N],ed,st[N],en[N],dfn,w[N]; char ch; inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';} inline void addedge(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;} void dfs(int x){ T[st[x]=++dfn].val=w[x],T[dfn].is=1; for(int i=g[x];i;i=nxt[i])dfs(v[i]); T[en[x]=++dfn].val=w[x]; } inline void add1(int x,ll p){ if(!x)return; T[x].val+=p;T[x].sum+=p*(T[x].ci-T[x].co);T[x].tag+=p; } inline void pb(int x){if(T[x].tag)add1(T[x].son[0],T[x].tag),add1(T[x].son[1],T[x].tag),T[x].tag=0;} inline void up(int x){ if(T[x].is)T[x].ci=1,T[x].co=0,T[x].sum=T[x].val;else T[x].ci=0,T[x].co=1,T[x].sum=-T[x].val; T[x].ci+=T[T[x].son[0]].ci+T[T[x].son[1]].ci; T[x].co+=T[T[x].son[0]].co+T[T[x].son[1]].co; T[x].sum+=T[T[x].son[0]].sum+T[T[x].son[1]].sum; } inline void rotate(int x){ int y=T[x].f,w=T[y].son[1]==x; T[y].son[w]=T[x].son[w^1]; if(T[x].son[w^1])T[T[x].son[w^1]].f=y; if(T[y].f){ int z=T[y].f; if(T[z].son[0]==y)T[z].son[0]=x; if(T[z].son[1]==y)T[z].son[1]=x; } T[x].f=T[y].f;T[x].son[w^1]=y;T[y].f=x;up(y); } inline void splay(int x,int w){ int s=1,i=x,y;a[1]=x; while(T[i].f)a[++s]=i=T[i].f; while(s)pb(a[s--]); while(T[x].f!=w){ y=T[x].f; if(T[y].f!=w){if((T[T[y].f].son[0]==y)^(T[y].son[0]==x))rotate(x);else rotate(y);} rotate(x); } if(!w)root=x; up(x); } int build(int l,int r,int fa){ int x=(l+r)>>1; T[x].f=fa; if(l==r){return up(x),x;} if(l<x)T[x].son[0]=build(l,x-1,x); if(r>x)T[x].son[1]=build(x+1,r,x); return up(x),x; } inline int get(int x,int y){ while(T[x].son[y])x=T[x].son[y]; return x; } inline void add(int x,int p){ splay(st[x],0); splay(en[x],root); add1(T[en[x]].son[0],p); T[en[x]].val+=p,up(en[x]); T[st[x]].val+=p,up(st[x]); } inline void move(int x,int y){ splay(st[x],0); int l=get(T[root].son[0],1); splay(en[x],0); int r=get(T[root].son[1],0); splay(l,0); splay(r,root); int t=T[r].son[0]; T[r].son[0]=0,up(r),up(l); splay(st[y],0); r=get(T[root].son[1],0); splay(st[y],0); splay(r,root); T[r].son[0]=t; T[t].f=r; up(r),up(root); } inline ll ask(int x){ splay(st[x],0); return T[T[root].son[0]].sum+T[root].val; } int main(){ read(n); for(i=2;i<=n;i++)read(x),addedge(x,i); for(i=1;i<=n;i++)read(w[i]); dfs(1); root=build(1,dfn,0); read(m); while(m--){ while(!(((ch=getchar())=='Q')||(ch=='C')||(ch=='F')));read(x); if(ch=='F')read(y),add(x,y); if(ch=='C')read(y),move(x,y); if(ch=='Q')printf("%lld\n",ask(x)); } return 0; }