动态树LCT是一种NB的数据结构,虽然不太好写。
与树链剖分类似,LCT把最后一个访问的儿子做为重边(暂且将Perferred Path叫做重边吧QAQ)。
对于一个由重边组成的链用序列之神Splay来维护。那么一棵LCT就有很多个Splay,然后每一个Splay的根都和它真实的父亲相连。在Splay中是将该点上面的点放在左儿子,下面的点放在右儿子。
具体的操作详见杨哲的SPOJ375 QTREE 解法的一些研究
当然那里面并没有将LCT的所有操作说完,比如说LCA,换根……
#include <iostream>
#include <cstdio>
#define MAXN 10005
using namespace std;
int n, m, a, b;
int stack[MAXN], tail;
int ch[MAXN][2], pre[MAXN], p[MAXN];
bool rev[MAXN];
char ask[5];
inline void rota(int x)
{
int y=pre[x], z=pre[y];
bool f=ch[y][1]==x;
ch[y][f]=ch[x][!f];
if(ch[y][f])pre[ch[y][f]]=y;
ch[x][!f]=y, pre[y]=x, pre[x]=z;
if(z)ch[z][ch[z][1]==y]=x;
}
inline void pushdown(int u)
{
if(rev[u])
{
rev[ch[u][0]]^=1, rev[ch[u][1]]^=1;
swap(ch[u][0],ch[u][1]);
rev[u]^=1;
}
}
void splay(int x)
{
for(int rt=x;rt;rt=pre[rt])stack[++tail]=rt;
while(tail)
pushdown(stack[tail--]);
while(pre[x])
{
p[x]=p[pre[x]];
p[pre[x]]=0;
rota(x);
}
}
void access(int u)
{
for(int v=0;u;u=p[u])
{
splay(u);
pre[ch[u][1]]=0;
p[ch[u][1]]=u;
ch[u][1]=v;
p[v]=0, pre[v]=u;
v=u;
}
}
int find_root(int u)
{
access(u);
splay(u);
while(ch[u][0])
u=ch[u][0];
return u;
}
void changeroot(int x)
{
access(x);
splay(x);
rev[x]^=1;
}
void join(int u,int v)
{
changeroot(u);
p[u]=v;
splay(u);
}
void cut(int u,int v)
{
changeroot(u);
access(v);
splay(v);
if(p[u]==v)p[u]=0;
else pre[u]=0, ch[v][ch[v][1]==u]=0;
}
int main()
{
scanf("%d%d",&n,&m);
while(m--)
{
scanf("%s%d%d",ask,&a,&b);
if(ask[0]=='Q')
{
if(find_root(a)==find_root(b))
puts("Yes");
else puts("No");
}
else if(ask[0]=='C')
join(a,b);
else
cut(a,b);
}
return 0;
}