BZOJ 2049 [Sdoi2008]Cave 洞穴勘测 LCT
2015-08-07 20:44
330 查看
题意:链接
方法: LCT
解析:
搞了一下午的LCT,这道题就当做第一道模板?题。然后大概写个理解总结什么的。
首先!splay不要写挂!不要写挂!
然后对于这道题。没有什么奇怪的操作。
只有两个操作,将两个节点连起来,将两个节点之间的连边断开。
每一次询问,询问两个节点是否连通。
听起来挺简单的,一下子就想到了并查集有没有!
然而发现并查集并不可以搞。
也许是我太弱,但是我真的不会并查集的分割。
所以还是老老实实来想LCT。
LCT 顾名思义,Link Cut 是其比较有代表性的操作?
首先我们定义几个函数。
access函数,代表的是从某个节点一直访问到其所在的splay的树根。并且将这一段链看作重链?
然后是splay,这就不说了。
movetoroot函数。
代表的是换根。也就是将x所在的splay里的根换为x。
这个函数怎么实现呢?
显然应该先访问该节点,确定好我们定义的重链。
之后将x旋到根。假设我们以深度为关键字。那我们旋转之后。该节点与树根之间的父子关系发生了对调。在以深度为关键字的splay tree中的体现就是所有的左右儿子对调,所以我们只要打一个reverse标记就可以了。
cut函数。
首先呢。我们要判断cut的两个节点(x,y)是否在同一棵splay tree里。
如果不在直接return。
然后我们把根换为x,访问以下y,之后把y旋到根。
这样的话。由于splay里是以深度为关键字。所以x一定在y的左儿子。
直接将二者连边干掉就行了。
link函数
把根换为x,然后直接令x的父亲为y就行了。
代码:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 10010 using namespace std; int ch [2]; int fa ; int rev ; int rt ; int n,m; void reverse(int x) { if(!x)return; rev[x]^=1; swap(ch[x][0],ch[x][1]); } void pushdown(int x) { if(rev[x]) { reverse(ch[x][0]); reverse(ch[x][1]); rev[x]=0; } } void down(int x) { if(!rt[x])down(fa[x]); pushdown(x); } void pushup(int x){} void rotate(int x) { int y=fa[x],kind=ch[y][1]==x; ch[y][kind]=ch[x][!kind]; fa[ch[y][kind]]=y; fa[x]=fa[y]; fa[y]=x; ch[x][!kind]=y; if(rt[y]) { rt[x]=1,rt[y]=0; }else ch[fa[x]][ch[fa[x]][1]==y]=x; pushup(y); } void splay(int x) { down(x); while(!rt[x]) { int y=fa[x],z=fa[y]; if(rt[y]) { rotate(x); }else if((ch[y][1]==x)==(ch[z][1]==y)) { rotate(y),rotate(x); }else { rotate(x),rotate(x); } } pushup(x); } void access(int x) { int y=0; while(x) { splay(x); rt[ch[x][1]]=1;rt[y]=0; ch[x][1]=y; pushup(x); y=x,x=fa[x]; } } int find_root(int x) { while(fa[x])x=fa[x]; return x; } void mt(int x) { access(x); splay(x); reverse(x); } void link(int x,int y) { mt(x); fa[x]=y; } void cut(int x,int y) { mt(x); access(y); splay(y); fa[x]=0; ch[y][0]=0; rt[x]=1; } void init(int x) { fa[x]=ch[x][0]=ch[x][1]=rev[x]=0; rt[x]=1; } char opt[25]; int main() { freopen("cave.in","r",stdin); freopen("cave.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)init(i); for(int i=1;i<=m;i++) { scanf("%s",opt); int x,y; scanf("%d%d",&x,&y); if(opt[0]=='Q') { if(find_root(x)==find_root(y))puts("Yes"); else puts("No"); }else if(opt[0]=='D')cut(x,y); else link(x,y); } }
相关文章推荐
- 11gR2更换OCR和VOTE
- python两个整数和浮点的方法来获取值
- 北大POJ_1050_To the Max
- 四大组件之Activity小结
- HDU 1166 树状数组
- 杭电 1686 Oulipo (kmp)
- 四大组件之Activity小结
- 最锋利的VS Web开发工具扩展:Web Essentials详解
- js使用经验之谈
- 概念与原理
- HDOJ 1358 Period(KMP next数组运用)
- poj1113 Wall 凸包
- 将Visual Studio打造成为Node.js IDE
- 前端页面一些应用
- (转)概念与原理
- UITableView 表视图
- 11、C语言和设计模式(外观模式)
- Tarena - 运算符与表达式
- 关于List l1 = new LinkedList();报错:不兼容的类型的问题的解决
- 考研