2018.10.07【SDOI2008】【BZOJ2049】【洛谷P2147】Cave洞穴勘測(LCT)
阿新 • • 發佈:2018-12-13
洛谷傳送門
解析:
這是一道的裸題,卻不夠板。
思路:
這是的一個經典應用,維護動態樹上節點的聯通性。 對於基本操作我不再贅述,詳見我的模板(暫未更新)。
這道題就講一講怎麼維護聯通性。
由於同一聯通塊中的節點是由幾條被維護的重鏈所覆蓋的,我們判斷連通性的時候只需要將一個節點變為該聯通子樹的根,然後判斷另一個節點的根是否是它就行了。
程式碼:
#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;
}