LCT维护子树信息(
考虑维护两个值,一个虚子树信息,一个全部信息。
因为虚子树只有在link和access的时候改变,可以方便的维护。
具体可以康康代码。
近期考虑写点大代码题练练手。

//Love and Freedom.
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
#define inf 20021225
#define fa(x) t[x].fa
#define ls(x) t[x].son[0]
#define rs(x) t[x].son[1]
#define nrt(x) (ls(fa(x))==x||rs(fa(x))==x)
#define N 100010
using namespace std;
int read()
{
int s=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return f*s;
}
struct node{int cnt,sum,fa,son[2]; bool tag;}t[N];
void pushup(int x){t[x].sum=1+t[x].cnt+t[ls(x)].sum+t[rs(x)].sum;}
void rotate(int x)
{
if(!nrt(x) || !x) return;
int f=fa(x),gf=fa(f);
int k=rs(f)==x,p=k^1;
if(nrt(f)) t[gf].son[rs(gf)==f]=x;
if(t[x].son[p]) t[t[x].son[p]].fa=f;
t[f].son[k]=t[x].son[p]; t[x].son[p]=f;
t[x].fa=gf; t[f].fa=x;
pushup(f); pushup(x);
}
void pushdown(int x)
{
if(t[x].tag)
{
swap(ls(x),rs(x));
if(ls(x)) t[ls(x)].tag^=1;
if(rs(x)) t[rs(x)].tag^=1;
t[x].tag=0;
}
}
void push(int x)
{
if(nrt(x)) push(fa(x));
pushdown(x);
}
void splay(int x)
{
push(x);
while(nrt(x))
{
int f=fa(x),gf=fa(f);
if(nrt(gf)) (rs(f)==x)^(rs(gf)==f)?rotate(x):rotate(f);
rotate(x);
}
}
void access(int x)
{
int y=0;
do
{
splay(x); t[x].cnt+=t[rs(x)].sum-t[y].sum;
rs(x)=y; pushup(x); y=x; x=fa(x);
}while(x);
}
void makeroot(int x)
{
access(x); splay(x); t[x].tag=1;
}
int getroot(int x)
{
access(x); splay(x);
while(ls(x)) x=ls(x);
return x;
}
void split(int x,int y)
{
makeroot(x); access(y); splay(y);
}
void link(int x,int y)
{
split(x,y);
if(getroot(y)==x) return;
t[x].fa=y; t[y].cnt+=t[x].sum;
}
ll calc(int x,int y)
{
split(x,y);
return 1ll*t[x].sum*(t[y].sum-t[x].sum);
}
char ch[10];
int main()
{
int n=read(),m=read();
for(int i=1;i<=n;i++) t[i].sum=1;
while(m--)
{
scanf("%s",ch); int x=read(),y=read();
if(ch[0]=='A') link(x,y);
else printf("%lld\n",calc(x,y));
}
return 0;
}
