Hdu 5967 小R与手机

LCT模板题

如果某一次加边会成环,我们可以保证这个点一定是某一个根,在根上记录一下后继

每一次切断某条边的之后同时查询根的是否有后继,后继是否可以连接

具体见代码

#include<bits/stdc++.h>
using namespace std;

const int maxn = 212345;

struct Node{
    int fa,son[2];
    int vedg;
    void init(){
        fa = son[0] = son[1] = 0;
        vedg = 0;
    }
}node[maxn];

int ori(int st){ 
    if(node[st].fa < 0) return 0;
    return st == node[node[st].fa].son[1]; 
}
void setc(int st,int sn,int d){
    if(st > 0) node[st].son[d] = sn; 
    if(sn > 0) node[sn].fa     = st;
}

void zg(int x){ 
    int st = node[x].fa;
    int p = node[st].fa;
    int d = ori(x) , dst=ori(st);

    setc(st,node[x].son[d^1],d);
    setc(x,st,d^1);
    setc(p,x,dst);
}

void splay(int x){
    #define f(x) (node[x].fa)
    while(f(x) > 0) {
        if(f(f(x)) <= 0) zg(x);
        else{ 
            if(ori(x) == ori(f(x))) 
                zg(f(x));
            else 
                zg(x);
            zg(x);
        }
    }
}

void access(int x){
    splay(x);
    while(node[x].fa < 0){
        int fa = -node[x].fa;
        splay(fa);
        node[node[fa].son[1]].fa *= -1;
        setc(fa,x,1);
        splay(x);
    }
}

int root(int x){
    access(x);
    while(node[x].son[0]) {
        x = node[x].son[0];
    }
    splay(x);
    return x;
}

void link(int st,int x){
    access(x);
    node[x].fa = -st;
    access(x);
}
void cut(int x){
    access(x);
    node[node[x].son[0]].fa = 0;
    node[x].son[0] = 0;
}

void Link(int st,int x){
    int rot = root(x);
    if(rot == x) node[rot].vedg = 0;
    else cut(x);
    int rv = node[rot].vedg;
    if(rv && root(rv) != rot){
        link(rv,rot);
        node[rot].vedg = 0;
    }
    if(root(st) == x) node[x].vedg = st;
    else link(st,x);
}



int main(){
    int n,m;
    scanf("%d %d",&n,&m);
    for(int i = 0 ; i <= n ; i ++)
        node[i].init();
    int x;
    for(int i = 1; i <= n; i ++){
        scanf("%d",&x);
        if(x) Link(x,i);
    }
    int ord,st;
    while(m--){
        scanf("%d %d",&ord,&x);
        if(ord == 2){
            x = root(x);
            printf("%d\n",node[x].vedg == 0 ? x : -1);
        }
        else{
            scanf("%d",&st);
            Link(st,x);
        }
    }
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值