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


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