BZOJ传送门
洛谷传送门
解析:
这是一道LCTLCTLCT的裸题,却不够板。
思路:
这是LCTLCTLCT的一个经典应用,维护动态树上节点的联通性。
对于基本操作我不再赘述,详见我的LCTLCTLCT模板(暂未更新)。
这道题就讲一讲怎么维护联通性。
由于同一联通块中的节点是由几条被SplaySplaySplay维护的重链所覆盖的,我们判断连通性的时候只需要将一个节点变为该联通子树的根,然后判断另一个节点的SplaySplaySplay根是否是它就行了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
inline
int getint(){
re int num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
return num;
}
inline
char getalpha(){
re char c;
while(!isalpha(c=gc()));
return c;
}
typedef struct splay_node *point;
struct splay_node{
point son[2],fa;
bool tag;
void init(){son[0]=son[1]=fa=NULL,tag=0;}
void pushdown(){
if(tag){
if(son[0])son[0]->tag^=1;
if(son[1])son[1]->tag^=1;
swap(son[0],son[1]);
tag=0;
}
}
point &lc(){return son[0];}
point &rc(){return son[1];}
bool isroot(){return !fa||(fa->lc()!=this&&fa->rc()!=this);}
bool which(){return this==fa->son[1];}
};
cs int N=10004;
struct Link_Cut_Tree{
point tr[N];
void init(int n){
for(int re i=0;i<=n;++i)
tr[i]=(point)malloc(sizeof(splay_node)),
tr[i]->init();
}
void Rotate(point now){
point Fa=now->fa,FA=Fa->fa;
if(FA&&!Fa->isroot())FA->son[Fa->which()]=now;
Fa->fa=now;
now->fa=FA;
bool pos=now==Fa->lc();
point tmp=now->son[pos];
if(tmp)tmp->fa=Fa;
Fa->son[!pos]=tmp;
now->son[pos]=Fa;
}
void Splay(point now){
static point q[N];
static int qn;
q[qn=1]=now;
for(point Fa=now;!Fa->isroot();Fa=Fa->fa)q[++qn]=Fa->fa;
for(int re i=qn;i;--i)q[i]->pushdown();
for(point Fa=now->fa;!now->isroot();Rotate(now),Fa=now->fa)
if(!Fa->isroot())Rotate(now->which()==Fa->which()?Fa:now);
}
void access(point now){
for(point son=NULL;now;son=now,now=now->fa){
Splay(now);now->rc()=son;
if(son)son->fa=now;
}
}
void makeroot(point now){
access(now);
Splay(now);
now->tag^=1;
}
point findroot(point now){
access(now);
Splay(now);
while(now->lc())now=now->lc();
return now;
}
void link(point u,point v){makeroot(u);u->fa=v;}
void Link(int u,int v){link(tr[u],tr[v]);}
void cut(point u,point v){
makeroot(u),access(v);
Splay(v);
u->fa=NULL;
v->lc()=NULL;
}
void Cut(int u,int v){cut(tr[u],tr[v]);}
bool connect(point u,point v){
makeroot(u);
point tmp=findroot(v);
return tmp==u;
}
bool Connect(int u,int v){return connect(tr[u],tr[v]);}
}LCT;
int n,m;
signed main(){
n=getint(),m=getint();
LCT.init(n);
while(m--){
char op=getalpha();
int u=getint(),v=getint();
switch(op){
case 'C':{
LCT.Link(u,v);
break;
}
case 'D':{
LCT.Cut(u,v);
break;
}
case 'Q':{
puts(LCT.Connect(u,v)?"Yes":"No");
break;
}
}
}
return 0;
}