【SDOI2008】【link-cut tree】洞穴勘测

来源:互联网 发布:中传女被害案 知乎 编辑:程序博客网 时间:2024/05/21 09:40

题目大意:维护一个森林中两点的连通性情况,有插入一条边和删除一条边两种操作

直接使用link-cut-tree维护森林的连通性即可。

注意在找出一条路径后需要维护splay上的翻转标记。

还有就是splay旋转的时候不能写把两种情况合在一句写,这样可能引起死循环!这个Bug我找了很久。以后一定要注意,见注释的那句话。

代码:

#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>using namespace std;const int maxn = 10000 + 10;int ch[maxn][2],pre[maxn];bool rev[maxn];int n,m;void init(){freopen("bzoj2049.in","r",stdin);freopen("bzoj2049.out","w",stdout);}void update(int x){if(rev[x]){swap(ch[x][0],ch[x][1]);rev[ ch[x][0] ] = !rev[ ch[x][0] ];rev[ ch[x][1] ] = !rev[ ch[x][1] ];rev[x] = false;}}void rotate(int x,int f){int y = pre[x],z = pre[y];ch[y][!f] = ch[x][f];pre[x] = pre[y];//if(pre[x])ch[ pre[y] ][ pre[y][1] == y ] = x;if(ch[z][0] == y)ch[z][0] = x;else if(ch[z][1] == y)ch[z][1] = x;pre[ ch[x][f] ] = y;pre[y] = x;ch[x][f] = y;update(y);}bool isroot(int x){return ch[pre[x]][0] != x && ch[pre[x]][1] != x;}void push_down(int x){if(!isroot(x))push_down(pre[x]);update(x);}void splay(int x){push_down(x);while(!isroot(x)){if(isroot(pre[x]))rotate(x,ch[pre[x]][0] == x);else{int y = pre[x],z = pre[y];int f = (ch[z][0] == y);if(ch[y][f] == x)rotate(x,!f),rotate(x,f);else rotate(y,f),rotate(x,f);}}update(x);}void access(int u){for(int v = 0;u;v = u,u = pre[u]){splay(u);ch[u][1] = v;update(u);}}void cut(int x,int y){access(y);splay(x);if(pre[x] == y)pre[x] = 0;else{access(x);splay(y);pre[y] = 0;}}void evert(int x){access(x);splay(x);rev[x] = !rev[x];}void link(int a,int b){evert(a);pre[a] = b;}bool query(int a,int b){int x = a,y = b;access(y);for(y = 0;x;x = pre[x]){splay(x);if(!pre[x])break;y = x;}for(;ch[x][1];x = ch[x][1]);return x == b;}void readdata(){memset(rev,false,sizeof(rev));memset(pre,0,sizeof(pre));scanf("%d%d",&n,&m);for(int i = 1;i <= m;i++){int a,b;char op[10];scanf("%s%d%d",op,&a,&b);if(op[0] == 'Q')puts(query(a,b) ? "Yes" : "No");if(op[0] == 'C')link(a,b);if(op[0] == 'D')cut(a,b);}}int main(){init();readdata();return 0;}