题意:
分析:
我们发现题意就是求一条边所连两个点各自的子树大小的乘积
但是关键问题来了,LCT 的本质是维护链的信息,那么怎么维护子树的信息呢?
常见操作就是新开一个数组用来记录子树信息( (siz,val) 等)
但是在 (link,access,cut) 这类修改 (splay) 形态的操作中,我们需要手动更改实虚儿子变化带来的影响,然后让影响 (pushup) 上去就可以了
- tip: (link) 里面原来的 (makeroot) 需要改成 (split) (等价于 (makeroot,access,splay)) 因为需要修改对 (y) 的影响所以要把 (y) 旋上去
代码:
#include<bits/stdc++.h>
using namespace std;
namespace zzc
{
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
const int maxn = 1e5+5;
int n,m,a,b;
char opt[5];
namespace lct
{
int top,q[maxn],c[maxn][2],fa[maxn],siz[maxn],rev[maxn],val[maxn];
void pushup(int x){siz[x]=siz[c[x][0]]+siz[c[x][1]]+val[x]+1;}
void pushdown(int x)
{
int l=c[x][0],r=c[x][1];
if(rev[x])
{
rev[l]^=1;rev[r]^=1;rev[x]^=1;
swap(c[x][0],c[x][1]);
}
}
bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}
void rotate(int x)
{
int y=fa[x],z=fa[y],l,r;
if(c[y][0]==x)l=0;else l=1;r=l^1;
if(!isroot(y)){if(c[z][0]==y)c[z][0]=x;else c[z][1]=x;}
fa[y]=x;fa[x]=z;fa[c[x][r]]=y;
c[y][l]=c[x][r];c[x][r]=y;
pushup(y);pushup(x);
}
void splay(int x)
{
top=1;q[top]=x;
for(int i=x;!isroot(i);i=fa[i]) q[++top]=fa[i];
for(int i=top;i;i--) pushdown(q[i]);
while(!isroot(x))
{
int y=fa[x],z=fa[y];
if(!isroot(y))
{
if((c[z][0]==y)^(c[y][0]==x)) rotate(x);
else rotate(y);
}
rotate(x);
}
}
void access(int x){for(int t=0;x;t=x,x=fa[x])splay(x),val[x]+=siz[c[x][1]]-siz[c[x][1]=t],pushup(x);}
void makeroot(int x){access(x);splay(x);rev[x]^=1;}
int find(int x){access(x);splay(x);while(c[x][0])x=c[x][0];splay(x);return x;}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void cut(int x,int y){split(x,y);if(c[y][0]==x&&c[x][1]==0)fa[x]=0,c[y][0]=0,pushup(y);}
void link(int x,int y){split(x,y);fa[x]=y;val[y]+=siz[x];pushup(y);}
}
using namespace lct;
void work()
{
n=read();m=read();
for(int i=1;i<=m;i++)
{
scanf("%s",opt);a=read();b=read();
if(opt[0]=='A') link(a,b);
else
{
split(a,b);
printf("%lld
",1ll*(val[a]+1)*(val[b]+1));
}
}
}
}
int main()
{
zzc::work();
return 0;
}