Link-Cut Tree维护。
每个点x维护以下信息:
v:这个点的点权
s:实链上的信息和
st:子树信息和(不包括链上)
sa:子树+链上的信息和
as:所有虚儿子的sa的和
则有
s[x]=v[x]+s[son[x][0]]+s[son[x][1]]
st[x]=as[x]+st[son[x][0]]+st[son[x][1]]
sa[x]=s[x]+st[x]
在access以及link的时候,涉及到虚实边的切换,在这个时候顺带维护一下as即可。
查询以x为根时y子树信息和的时候,将x作为根,然后access(y),此时答案=as[y]+v[y]。
时间复杂度$O(mlog n)$。
#include<cstdio> #define N 200010 typedef long long ll; int n,m,i,op,x,y,z; int f[N],son[N][2],tmp[N],c[N];bool rev[N]; ll v[N],s[N],mx[N],tc[N],ta[N]; ll st[N],sa[N],as[N]; 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 umax(ll&a,ll b){if(a<b)a=b;} inline void swap(int&a,int&b){int c=a;a=b;b=c;} inline bool isroot(int x){return !f[x]||son[f[x]][0]!=x&&son[f[x]][1]!=x;} inline void rev1(int x){if(!x)return;swap(son[x][0],son[x][1]);rev[x]^=1;} inline void col1(int x,ll y){ if(!x)return; v[x]=mx[x]=tc[x]=y; s[x]=y*c[x]; ta[x]=0; sa[x]=s[x]+st[x]; } inline void add1(int x,ll y){ if(!x)return; v[x]+=y; s[x]+=y*c[x]; mx[x]+=y; if(tc[x])tc[x]+=y;else ta[x]+=y; sa[x]=s[x]+st[x]; } inline void pb(int x){ if(rev[x])rev1(son[x][0]),rev1(son[x][1]),rev[x]=0; if(tc[x])col1(son[x][0],tc[x]),col1(son[x][1],tc[x]),tc[x]=0; if(ta[x])add1(son[x][0],ta[x]),add1(son[x][1],ta[x]),ta[x]=0; } inline void up(int x){ s[x]=mx[x]=v[x];c[x]=1; st[x]=as[x]; for(int i=0;i<2;i++){ int y=son[x][i]; if(y){ c[x]+=c[y]; s[x]+=s[y]; umax(mx[x],mx[y]); st[x]+=st[y]; } } sa[x]=s[x]+st[x]; } inline void rotate(int x){ int y=f[x],w=son[y][1]==x; son[y][w]=son[x][w^1]; if(son[x][w^1])f[son[x][w^1]]=y; if(f[y]){ int z=f[y]; if(son[z][0]==y)son[z][0]=x;else if(son[z][1]==y)son[z][1]=x; } f[x]=f[y];f[y]=x;son[x][w^1]=y;up(y); } inline void splay(int x){ int s=1,i=x,y;tmp[1]=i; while(!isroot(i))tmp[++s]=i=f[i]; while(s)pb(tmp[s--]); while(!isroot(x)){ y=f[x]; if(!isroot(y)){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);} rotate(x); } up(x); } inline void access(int x){ for(int y=0;x;y=x,x=f[x]){ splay(x); if(son[x][1])as[x]+=sa[son[x][1]]; if(son[x][1]=y)as[x]-=sa[y]; up(x); } } inline void makeroot(int x){access(x);splay(x);rev1(x);} inline void link(int x,int y){ makeroot(x); makeroot(y); as[y]+=sa[x]; f[x]=y; access(x); } inline void cutf(int x){access(x);splay(x);f[son[x][0]]=0;son[x][0]=0;up(x);} inline void cut(int x,int y){makeroot(x);cutf(y);} inline void col(int x,int y,int z){makeroot(x);access(y);splay(y);col1(y,z);} inline void add(int x,int y,int z){makeroot(x);access(y);splay(y);add1(y,z);} inline ll chainsum(int x,int y){makeroot(x);access(y);splay(y);return s[y];} inline ll chainmax(int x,int y){makeroot(x);access(y);splay(y);return mx[y];} inline ll subtreesum(int x,int y){makeroot(x);access(y);splay(y);return as[y]+v[y];} int main(){ read(n); for(i=1;i<=n;i++)read(x),v[i]=s[i]=mx[i]=sa[i]=x,c[i]=1; for(i=2;i<=n;i++)read(x),link(x,i); read(m); while(m--){ read(op),read(x),read(y); if(op==1)read(z),add(x,y,z); if(op==2)read(z),col(x,y,z); if(op==3)printf("%lld ",subtreesum(x,y)); if(op==4)printf("%lld ",chainmax(x,y)); if(op==5)printf("%lld ",chainsum(x,y)); if(op==6)link(x,y); if(op==7)cut(x,y); } return 0; }