bzoj2049: [Sdoi2008]Cave 洞穴勘测

题目链接

bzoj2049

题意

初始时给定一个n个点的森林,支持3个操作。
Connect x y:将x与y间连一条边。 保证连边之后任然是一颗树。
Destroy x y :将x与y间的边删去。 保证x与y有边相连。
Query x y :询问x与y是否联通。
N<=10000。 询问M<=200000。

题解

link-cut tree。 学习请点这里。
需要注意的有连接两棵树x与y时之前深度小于x的节点的深度都将大于x,因此需要将x的子树翻转,打个标记即可,但在splay之前要将x到root间的路径都更新。
之前记录了一个root[i]表示i号点是否是根,结果写的时候各种忘记更新root。最后发现只要i的父亲的左右儿子都不是i,那么i就是根,这样就省了很多事。

这里贴代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;

#define maxn 10100
int son[maxn][2],f[maxn],rev[maxn],n,m,x,y;
char s[10];
#define root(x) (son[f[x]][0]!=x&&son[f[x]][1]!=x)
//判断x是否为根。
void updata(int x){
    if(rev[x]==0)return;
    swap(son[x][1],son[x][0]); rev[x]=0;
    rev[son[x][0]]^=1; rev[son[x][1]]^=1;
}

void push_down(int x){  //更新x到根的路径。
    if(!root(x))push_down(f[x]);
    updata(x);
}

void rt(int x,int k){
    int y=f[x],z=f[y];
    son[y][k^1]=son[x][k];
    f[son[x][k]]=y;
    son[x][k]=y;
    f[y]=x; f[x]=z;
    if(son[z][0]==y)son[z][0]=x;
    else if(son[z][1]==y)son[z][1]=x;
    updata(y);
    updata(x);
}

void splay(int x){
    push_down(x);
    while(!root(x)){
        int y=f[x],z=f[y];
        if(root(y)&&son[y][0]==x)rt(x,1);
        else if(root(y)&&son[y][1]==x)rt(x,0);
        else if(son[z][0]==y&&son[y][0]==x)rt(y,1),rt(x,1);
        else if(son[z][0]==y&&son[y][1]==x)rt(x,0),rt(x,1);
        else if(son[z][1]==y&&son[y][0]==x)rt(x,1),rt(x,0);
        else rt(y,0),rt(x,0);
    }
}

void access(int x){
    for(int y=0;x;x=f[x]){
        splay(x);
        son[x][1]=y;
        updata(x);
        y=x;
    }
}

void link(int x,int y){
    access(x); splay(x);
    rev[x]^=1;
    f[x]=y;
    updata(x); 
}

void cut(int x,int y){
    access(x);
    splay(y);
    if(f[y]==x)f[y]=0;
    else{
        access(y);
        splay(x);
        f[x]=0;
    }
}

bool connected(int x,int y){
    access(x); splay(x);
    while(son[x][0])x=son[x][0];
    access(y); splay(y);
    while(son[y][0])y=son[y][0];
    return x==y;
}

int main(){
    //freopen("cave.in","r",stdin);
    //freopen("cave.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%s%d%d",s,&x,&y);
        if(s[0]=='C')link(x,y);
        else if(s[0]=='D')cut(x,y);
        else if(connected(x,y))puts("Yes");
        else puts("No");
    }
    return 0;
}

你可能感兴趣的:(LCT)