bzoj2049[洞穴勘測]純粹的LCT

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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章