BZOJ 2049, 洞穴勘测

14 篇文章 0 订阅
1 篇文章 0 订阅
该博客主要介绍了如何使用LCT数据结构解决BZOJ 2049洞穴勘测问题,包括动态连边、删边和查询两点连通性操作。博主探讨了LCT相对于并查集的优势,并提供了参考资料链接,通过一道题目学习和回顾了LCT和Splay树的相关知识。
摘要由CSDN通过智能技术生成

Problem

传送门

Mean

要求编写一个数据结构,支持动态连边、删边和查询两点连通性。
保证两点间最多只有一条路径。

Analysis

LCT模板题。
(其实并查集更好些?)
借这题大致了解了一下LCT,顺便回顾了一下Splay。
LCT里的Splay略有不同于普通的Splay,也是需要特别注意的。

参考资料:Yang Zhe《SPOJ375 QTREE 解法的一些研究》

Code

#include<cstdio>
const int N=10005;
int n,m,x,y,f[N],son[N][2],tmp[N];
bool rev[N];
char s[10];
int read(){
    char c;
    while((c=getchar())<'0' || c>'9');
    int x=c-'0';
    while((c=getchar())>='0' && c<='9') x=x*10+c-'0';
    return x;
}
bool isroot(int x){return !f[x] || son[f[x]][0]!=x && son[f[x]][1]!=x;}
void swap(int &x,int &y){int t=x;x=y,y=t;}
void revl(int x){if(!x) return;swap(son[x][0],son[x][1]);rev[x]^=1;}
void pb(int x){if(rev[x]) revl(son[x][0]),revl(son[x][1]),rev[x]=0;}
void rotate(int x){
    int y=f[x],w=son[y][1]==x;
    son[y][w]=son[x][w^1];
    if(son[x][w^1]) f[son[x][w^1]]=y;
    if(!isroot(y)) son[f[y]][son[f[y]][1]==y]=x;
    f[x]=f[y];f[y]=x;son[x][w^1]=y;
}
void splay(int x){
    int s=1,i=x,y;
    tmp[1]=i;
    while(!isroot(i)) tmp[++s]=i=f[i];
    while(s) pb(tmp[s--]);
    while(!isroot(x)){
        y=f[x];
        if(!isroot(y)){
            if((son[f[y]][0]==y)^(son[y][0]==x)) rotate(x);
            else rotate(y);
        }
        rotate(x);
    }
}
void access(int x){for(int y=0;x;y=x,x=f[x]) splay(x),son[x][1]=y;}
int root(int x){access(x);splay(x);while(son[x][0]) x=son[x][0];return x;}
void makeroot(int x){access(x);splay(x);revl(x);}
void link(int x,int y){makeroot(x);f[x]=y;access(x);}
void cutf(int x){access(x);splay(x);f[son[x][0]]=0;son[x][0]=0;}
void cut(int x,int y){makeroot(x);cutf(y);}
int main(){
    n=read(),m=read();
    while(m--){
        scanf("%s",s);
        x=read(),y=read();
        if(s[0]=='C') link(x,y);
        else if(s[0]=='D') cut(x,y);
        else if(root(x)!=root(y)) printf("No\n");
        else printf("Yes\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值