bzoj2049[洞穴勘测]纯粹的LCT

来源:互联网 发布:iphone微信定位软件 编辑:程序博客网 时间:2024/06/02 10:20

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


0 0
原创粉丝点击