#include<cstdio>
#include<iostream>
using namespace std;
const int N=2e5+5;
int f[N],ch[N][2],st[N],tag[N];
int sum[N],sz[N];//sum:一个点在其所在splay中 左儿子的个数+右儿子的个数+所有的虚儿子的总信息+1(该节点)
inline void pushup(int x){
sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+sz[x]+1;//该点的所有信息
}
inline void pushdown(int x){
if(!tag[x]) return;
swap(ch[ch[x][0]][0],ch[ch[x][0]][1]),tag[ch[x][0]]^=1;
swap(ch[ch[x][1]][0],ch[ch[x][1]][1]),tag[ch[x][1]]^=1;
tag[x]=0;
}
inline int notroot(int x){//不是当前所在splay的根
return ch[f[x]][0]==x||ch[f[x]][1]==x;
}
inline void route(int x){
int y=f[x],z=f[y],w=(ch[y][1]==x);
if(notroot(y)) ch[z][ch[z][1]==y]=x;//先这句话!!!
f[x]=z;
ch[y][w]=ch[x][w^1];if(ch[y][w]) f[ch[y][w]]=y;
ch[x][w^1]=y,f[y]=x;
pushup(y),pushup(x);
}
inline void splay(int x){
int y=x,num=0;st[++num]=y;
while(notroot(y)) st[++num]=(y=f[y]);
while(num) pushdown(st[num--]);
if(!notroot(x)) return;
for(int fa=f[x];notroot(x);route(x),fa=f[x])
if(notroot(fa)) ((ch[fa][1]==x)^(ch[f[fa]][1]==fa))?route(x):route(fa);
}
inline void access(int x){
for(int y=0;x;x=f[y=x])
splay(x),sz[x]+=sum[ch[x][1]]-sum[y],ch[x][1]=y,pushup(x);//更新sz[x]
}
inline void makeroot(int x){
access(x),splay(x);
swap(ch[x][0],ch[x][1]),tag[x]^=1;
}
inline int findroot(int x){
access(x),splay(x);
while(ch[x][0]) pushdown(x),x=ch[x][0];
splay(x);
return x;
}
inline void link(int x,int y){
makeroot(x),makeroot(y),f[y]=x,sz[x]+=sum[y],pushup(x);//一定要x y都要makeroot
}
int main(){
// freopen("dynamic_tree.in","r",stdin);
// freopen("dynamic_tree.out","w",stdout);
int n,m,typ,u,v;scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) sum[i]=1;
while(m--){
scanf("%d%d",&typ,&u);
if(typ==1) makeroot(u);
if(typ==2) access(u),printf("%d\n",sz[u]+1);//它的子树全部变成他的虚儿子
if(typ==3){
scanf("%d",&v);int root=findroot(u);
link(u,v),makeroot(root);
}
}
}
cogs 2701. 动态树(lct 维护子树信息(大小)模板)
最新推荐文章于 2022-05-16 00:00:00 发布