Solution
首先边((x,y))的负载显然可以转化为,(x,y)所在树中,((x)的子树大小(-y)的子树大小)(*y)的子树大小(假设(x)是(y)的父亲)
我们想用(LCT)来维护这样的东西,但之前我们提到过,(LCT)维护子树信息十分困难,但子树和这样的也是比较好处理的:
显然子树和可以由实子树和和虚子树和组成,于是考虑用(sum1)维护子树和,(sum2)维护虚子树和,那么(pushup)就很好写了:
inline void pushup(int x){
sum1[x]=sum1[ch[x][0]]+sum1[ch[x][1]]+1+sum2[x];
}
接下来考虑我们什么时候改变了(sum2),其实只有两个地方:
(1.access)
(access)过程中,我们将每个点(x)的右儿子改变,(sum2)自然就会增加原来右儿子的子树和,减去新的右儿子的子树和:
inline void access(int x){
for(int last=0;x;last=x,x=fa[x]){
Splay(x);
sum2[x]+=sum1[ch[x][1]];
sum2[x]-=sum1[last];
ch[x][1]=last;
pushup(x);
}
}
(2.link)
(link)过程中,我们在((x,y))间连了一条轻边,于是要在(y)的(sum2)中增加(x)所在树的点权和:
inline void link(int x,int y){
split(x,y); //split其实就是完成了正常link的makeroot操作并且将x到y的链找出来
sum2[y]+=sum1[x];
fa[x]=y;
}
其它的就是模板了.
Code
#include<bits/stdc++.h>
using namespace std;
const int N=4e5+10;
int n,sum1[N],ch[N][2],fa[N],rev[N],sum2[N];//sum1为所有子树siz之和,sum2为虚子树siz之和
inline bool which(int x){return ch[fa[x]][1]==x;}
inline void pushup(int x){
sum1[x]=sum1[ch[x][0]]+sum1[ch[x][1]]+1+sum2[x];
}
inline bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
inline void rever(int x){
swap(ch[x][0],ch[x][1]);
rev[x]^=1;
}
inline void pushdown(int x){
if(!rev[x]) return ;
if(ch[x][0]) rever(ch[x][0]);
if(ch[x][1]) rever(ch[x][1]);
rev[x]=0;
}
inline void Rotate(int x){
int y=fa[x],z=fa[y],wx=which(x),wy=which(y);
if(!isroot(y)) ch[z][wy]=x;fa[x]=z;
ch[y][wx]=ch[x][wx^1];
if(ch[y][wx]) fa[ch[y][wx]]=y;
ch[x][wx^1]=y;fa[y]=x;
pushup(y);
}
int stk[N],top;
inline void Splay(int x){
int now=x;
stk[top=1]=now;
while(!isroot(now)) now=fa[now],stk[++top]=now;
while(top) pushdown(stk[top--]);
while(!isroot(x)){
int y=fa[x];
if(!isroot(y)){
if(which(x)==which(y)) Rotate(y);
else Rotate(x);
}Rotate(x);
}
pushup(x);
}
inline void access(int x){
for(int last=0;x;last=x,x=fa[x]){
Splay(x);
sum2[x]+=sum1[ch[x][1]];
sum2[x]-=sum1[last];
ch[x][1]=last;
pushup(x);
}
}
inline void makeroot(int x){
access(x);Splay(x);
rever(x);
}
inline void split(int x,int y){
makeroot(x);
access(y);Splay(y);
}
inline void link(int x,int y){
split(x,y);
sum2[y]+=sum1[x];
fa[x]=y;
}
int q;
char op[10];
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;++i) sum1[i]=1;
while(q--){
int x,y;
scanf("%s%d%d",op,&x,&y);
if(op[0]=='A') link(x,y);
else makeroot(y),access(x),Splay(y),printf("%lld
",1ll*(sum1[y]-sum1[x])*(sum1[x]));
}
return 0;
}