正题
你会发现把一条边split之后他就只成为了一棵两点一线的splay。
所以直接维护虚子树的和就可以了。
#include<bits/stdc++.h>
#define ls son[x][0]
#define rs son[x][1]
using namespace std;
const int N=100010;
int n,q;
int son[N][2],fa[N],sz[N],rev[N],size[N];
int sta[N],top;
bool isroot(int x){
return son[fa[x]][0]!=x && son[fa[x]][1]!=x;
}
void update(int x){
size[x]=size[ls]+size[rs]+sz[x]+1;
}
void pushdown(int x){
if(!rev[x]) return ;
rev[x]=0;rev[ls]^=1;rev[rs]^=1;
swap(son[ls][0],son[ls][1]);
swap(son[rs][0],son[rs][1]);
}
void rotate(int x){
int f=fa[x],ff=fa[f];
int w=(son[f][0]==x);
if(!isroot(f)){
if(son[ff][0]==f) son[ff][0]=x;
else son[ff][1]=x;
}fa[x]=ff;
son[f][1-w]=son[x][w];
if(son[x][w]) fa[son[x][w]]=f;
son[x][w]=f;fa[f]=x;
update(f);update(x);
}
void splay(int x){
sta[top=1]=x;
for(int i=x;!isroot(i);i=fa[i]) sta[++top]=fa[i];
for(int i=top;i>=1;i--) pushdown(sta[i]);
while(!isroot(x)){
if(!isroot(fa[x])){
if((son[fa[x]][0]==x) ^ (son[fa[fa[x]]][0]==fa[x])) rotate(x);
else rotate(fa[x]);
}
rotate(x);
}
}
void access(int x){
for(int y=0;x;y=x,x=fa[x])
splay(x),sz[x]+=size[rs],sz[x]-=size[rs=y];
}
void makeroot(int x){
access(x);splay(x);rev[x]^=1;swap(son[x][0],son[x][1]);
}
void split(int x,int y){
makeroot(x);access(y);splay(y);
}
void link(int x,int y){
split(x,y);
fa[x]=y;sz[y]+=size[x];update(y);
}
int main(){
scanf("%d %d",&n,&q);
char ch[4];
int x,y;
for(int i=1;i<=n;i++) size[i]=1;
while(q--){
scanf("%s %d %d",ch,&x,&y);
if(ch[0]=='A') link(x,y);
else {
split(x,y);
printf("%lld\n",1ll*(sz[x]+1)*(sz[y]+1));
}
}
}

被折叠的 条评论
为什么被折叠?



