LCT
bool check(int x)
{
return ch[fa[x]][1]==x;
}
void pushrev(int x)
{
rev[x]^=1,swap(ch[x][0],ch[x][1]);
}
void pushup(int x)
{
sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+val[x];
}
void pushdown(int x)
{
if(!rev[x]) return;
pushrev(ch[x][0]),pushrev(ch[x][1]);
rev[x]=0;
}
bool notroot(int x)
{
return ch[fa[x]][0]==x||ch[fa[x]][1]==x;
}
void rotate(int x)
{
int y=fa[x],z=fa[y],k=check(x),w=ch[x][k^1];
if(notroot(y)) ch[z][check(y)]=x;
ch[x][k^1]=y,ch[y][k]=w;
if(w) fa[w]=y;
fa[x]=z,fa[y]=x;
pushup(y),pushup(x);
}
void all(int x)
{
if(notroot(x)) all(fa[x]);
pushdown(x);
}
void splay(int x)
{
all(x);
for(int y;notroot(x);rotate(x))
if(notroot(y=fa[x]))
rotate(check(x)^check(y)?x:y);
pushup(x);
}
void access(int x)
{
for(int y=0;x;y=x,x=fa[x])
splay(x),ch[x][1]=y,pushup(x);
}
void makeroot(int x)
{
access(x),splay(x),pushrev(x);
}
void split(int x,int y)
{
makeroot(x),access(y),splay(y);
}
int findroot(int x)
{
access(x),splay(x);
while(ch[x][0]) x=ch[x][0];
splay(x);
return x;
}
void link(int x,int y)
{
makeroot(x);
if(findroot(y)!=x) fa[x]=y;
}
void cut(int x,int y)
{
makeroot(x);
if(findroot(y)==x&&fa[y]==x&&!ch[y][0])
fa[y]=ch[x][1]=0;
}
int query(int x,int y)
{
split(x,y);
return sum[y];
}
若连边和删边合法
void link(int x,int y)
{
split(x,y),fa[x]=y;
}
void cut(int x,int y)
{
split(x,y),fa[x]=ch[y][0]=0;
}
维护子树信息
void pushup(int x)
{
siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+s[x]+val[x];
}
void access(int x)
{
for(int y=0;x;y=x,x=fa[x])
splay(x),s[x]+=siz[ch[x][1]]-siz[ch[x][1]=y];
}
void link(int x,int y)
{
split(x,y),s[fa[x]=y]+=siz[x];
}