BZOJ 2049 [Sdoi2008]Cave 洞穴勘测
AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=2049
[分析]
这题仍然也是不需要转化模型的单纯维护森林的问题 [因为两点之间至多一条路径嘛].
所以仍然是考验LCT的代码与重要函数的实现.
这次主要进行的操作多了Cut(u,v)\Link(u,v)\Query(u,v)
分别作用是删除边(u,v),连接边(u,v),判断两点是否在同一棵树中[在同一棵树中 <=> 两点间有通路]
首先说一个新的名叫make_root(x)的辅助性操作,指让x成为x所在树的根
就是先Access(x),使其与根连通,而且是所在链上深度最大的,然后在所在splay上打下翻转tag,它就成了根
删除边稍微难想一些:
添边:
为了满足要求,先将u变成所在树的树根,然后再连上v就好了
询问:
直接向上回溯...没什么好说的.
这样说应该有些抽象,具体欢迎看代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=10010; inline int in(){ int x=0;char ch=getchar(); while(ch>'9' || ch<'0') ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar(); return x; } char ord[8]; struct Node{ int l,r,f; bool rt,rv; void trans(){ swap(l,r);} }s[maxn]; void push_down(int x){ if(s[x].rv){ s[x].trans(); if(s[x].l) s[s[x].l].rv^=1; if(s[x].r) s[s[x].r].rv^=1; s[x].rv=0; } } void down_tag(int x){ if(!s[x].rt) down_tag(s[x].f); push_down(x); } void zig(int x){ int y=s[x].f; s[x].f=s[y].f; if(s[y].rt) s[y].rt=false,s[x].rt=true; else{ if(y==s[s[y].f].l) s[s[y].f].l=x; else s[s[y].f].r=x;} s[y].l=s[x].r; if(s[x].r) s[s[x].r].f=y; s[x].r=y,s[y].f=x; } void zag(int x){ int y=s[x].f; s[x].f=s[y].f; if(s[y].rt) s[y].rt=false,s[x].rt=true; else{ if(y==s[s[y].f].l) s[s[y].f].l=x; else s[s[y].f].r=x;} s[y].r=s[x].l; if(s[x].l) s[s[x].l].f=y; s[x].l=y,s[y].f=x; } void Splay(int x){ down_tag(x); int y; while(!s[x].rt){ y=s[x].f; if(s[y].rt){ if(x==s[y].l) zig(x); else zag(x);} else{ int z=s[y].f; if(y==s[z].l){ if(x==s[y].l) zig(y),zig(x); else zag(x),zig(x);} else { if(x==s[y].r) zag(y),zag(x); else zig(x),zag(x);} } } } void Access(int x){ for(int last=0;x;x=s[last=x].f){ Splay(x); s[s[x].r].rt=true; s[x].r=last; s[last].rt=false; } } /* make_rt(x)操作表示将x作为x所在树的根 当Access和Splay操作完后,这个点处于平衡树的顶端而且没有右儿子[切断了联系] 那么将正棵平衡树翻转一下就让x作为正棵树的最左端点了[没有左儿子] */ void make_rt(int x){ Access(x); Splay(x); s[x].rv^=1; } bool query(int u,int v){ while(s[u].f) u=s[u].f; while(s[v].f) v=s[v].f; return u==v; } void Link(int u,int v){ make_rt(u); s[u].f=v; } void Cut(int u,int v){ make_rt(u); Access(v); Splay(v); s[s[v].l].f=s[v].f; s[s[v].l].rt=true; s[v].f=s[v].l=0; } int n,m; int main(){ #ifndef ONLINE_JUDGE freopen("2049.in","r",stdin); freopen("2049.out","w",stdout); #endif int u,v; n=in(),m=in(); for(int i=1;i<=n;i++) s[i].rt=true; while(m--){ scanf("%s",ord);u=in(),v=in(); if(ord[0]=='Q'){ if(query(u,v)) puts("Yes"); else puts("No"); } else if(ord[0]=='C') Link(u,v); else Cut(u,v); } return 0; }