http://www.lydsy.com/JudgeOnline/problem.php?id=2049
就像lct=link-cut-tree一樣,這道題是純粹的LCT.爲什麼呢,它的操作一共就只有link,cut.(query是查詢)
可以說是非常的裸,但是對於我這個剛學的菜鳥還是有一個地方比較糾結
首先初始化所有的點,是他們各自是一棵樹。
然後一旦兩個點兩邊就link兩個森林。
link操作是一樣的,access(u),splay(u),u->rev=1,u->f=v. 思想不變
query操作 就分別找兩棵樹的splay上的根,判斷是否相同
唯一糾結的就是cut操作,不清楚誰是誰的父親
這說明我並沒有弄清楚LCT的實質。
對於一棵splay,隨便選哪棵做根都可以,於是我們考慮把u設爲根(這棵樹),然後access(v),得到u-v的路徑,然後splay(v),v的左邊一定是比u深度小的,而u-v直接相連並且u爲整棵樹的根,所以在splay中v作根,v的左兒子一定就是u了。
然後這道題就是模板題了:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
const int maxn=10000+5;
/*
洞穴勘測:標準的link-cut-tree
*/
int n,m;
struct node
{
node *f;
node *ch[2];
bool rev;
}tree[maxn],*null,Tnull;
void init(node *u)
{
u->f=u->ch[0]=u->ch[1]=null;
u->rev=0;
}
bool isroot(node *u)
{
return u==null||u->f->ch[0]!=u&&u->f->ch[1]!=u;
}
void pushdown(node *u)
{
if(u==null)return ;
if(u->rev)
{
swap(u->ch[0],u->ch[1]);
if(u->ch[0]!=null)u->ch[0]->rev^=1;
if(u->ch[1]!=null)u->ch[1]->rev^=1;
u->rev=0;
}
}
void rotate(node *u)
{
node *f=u->f;
node *ff=f->f;
int d=u==f->ch[1];
if(u->ch[d^1]!=null)u->ch[d^1]->f=f;
f->ch[d]=u->ch[d^1];
u->f=ff;
if(ff!=null)
{
if(f==ff->ch[0])ff->ch[0]=u;
else if(f==ff->ch[1])ff->ch[1]=u;
}
u->ch[d^1]=f;
f->f=u;
}
int cnt;
node *sta[maxn];
void splay(node *u)
{
if(u==null)return ;
cnt=1;
sta[0]=u;
for(node *y=u;!isroot(y);y=y->f)
{
sta[cnt++]=y->f;
}
while(cnt)pushdown(sta[--cnt]);
while(!isroot(u))
{
node *f=u->f;
if(isroot(f))
{
rotate(u);
}
else
{
node *ff=f->f;
int d=u==f->ch[1];
int dd=f==ff->ch[1];
if(d==dd)rotate(f);
else rotate(u);
rotate(u);
}
}
}
node *access(node *u)
{
node *v=null;
while(u!=null)
{
splay(u);
u->ch[1]=v;
v->f=u;
v=u;
u=u->f;
}
return v;
}
bool sam(node *u,node *v)
{
while(u->f!=null)u=u->f;
while(v->f!=null)v=v->f;
return u==v;
}
void link(node *u,node *v)
{
access(u);
splay(u);
u->rev=1;
u->f=v;
}
void changeroot(node *u)
{
access(u)->rev^=1;
}
void cut(node *u,node *v)
{
changeroot(u);
access(v);
splay(v);
v->ch[0]=v->ch[0]->f=null;
}
char ss[20];
int main()
{
null=&Tnull;
init(null);
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=1;i<=n;i++)
{
init(&tree[i]);
}
int u,v;
for(int i=1;i<=m;i++)
{
scanf("%s%d%d",ss,&u,&v);
if(ss[0]=='Q')
{
bool ok=sam(tree+u,tree+v);
if(ok)printf("Yes\n");
else printf("No\n");
}
else if(ss[0]=='C')
{
link(tree+u,tree+v);
}
else if(ss[0]=='D')
{
cut(tree+u,tree+v);
}
}
}
return 0;
}