2049: [Sdoi2008]Cave 洞穴勘测

题目链接

题目大意:动态树,要求link,cut,查询两点连通性

题解:LCT,对于query操作,查询x在原树的根就好了。并查集乱搞能过……

我的收获:LCTget

#include <iostream>
#include <cstdio>
#define M 100005
using namespace std;

int n,m,y;
int fa[M],c[M][2],st[M];
bool rev[M];

inline bool f(int x){return c[fa[x]][1]==x;}

inline bool isr(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}

void pushdown(int x)
{
    if(!rev[x]) return ;
    int &l=c[x][0],&r=c[x][1];
    rev[l]^=1;rev[r]^=1;swap(l,r);
    rev[x]=0;
}

void rotate(int x)
{
    int p=fa[x],g=fa[p],r;
    bool k=f(x),m=f(p);r=c[x][k^1];
    if(!isr(p)) c[g][m]=x;
    fa[x]=g,c[x][k^1]=p;
    fa[p]=x,c[p][k]=r;
    if(r) fa[r]=p;
}

void maintain(int x)
{
    int top=0;st[++top]=x;
    for(int i=x;!isr(i);i=fa[i]) st[++top]=fa[i];
    for(int i=top;i;i--) pushdown(st[i]);
}

void splay(int x)
{
    maintain(x);
    for(;!isr(x);rotate(x))
        if(!isr(fa[x])) rotate(f(x)==f(fa[x])?fa[x]:x);
}

void access(int x){for(y=0;x;c[x][1]=y,y=x,x=fa[x]) splay(x);}//取出当前点到当前根的这一段路径,将它们放到一个Splay中。

void rever(int x){access(x);splay(x);rev[x]^=1;}//将x旋转到其所在树的树根 

void link(int x,int y){rever(y);fa[y]=x;}//将y连到x的下面 

void cut(int x,int y){rever(x);access(y);splay(y);fa[x]=c[y][0]=0;}//断开x和y之间的边 

int fdrt(int x)//找x在原树中的根结点 
{
    access(x);splay(x);
    for(y=x;c[y][0];y=c[y][0]);
    return y;
}

void work()
{
    int x,y;
    char opt[10];
    while(m--)
    {
        scanf("%s",opt);
        scanf("%d%d",&x,&y);
        if(opt[0]=='C')link(x,y);
        else if(opt[0]=='D')cut(x,y);
        else puts(fdrt(x)==fdrt(y)?"Yes":"No");
    }
}

void init(){
    cin>>n>>m;
}

int main()
{
    init();
    work();
    return 0;
}

HOME Back 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值