bzoj3674: 可持久化并查集加强版(主席树+并查集)

本文介绍了一种使用主席树优化的可持久化并查集实现方法,支持历史版本连边和连通性查询,通过按秩合并策略提高效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门
题意:维护可持久化并查集,支持在某个版本连边,回到某个版本,在某个版本 询问连通性。


思路:
我们用主席树维护并查集 f a fa fa数组,由于要查询历史版本,因此不能够用路径压缩。
可以考虑另外一种优化方式:按秩合并貌似直接瞎合并也能过
于是主席树再额外维护一个该节点的秩即可。
代码:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
inline int read(){
    int ans=0;
    char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
    return ans;
}
const int N=2e5+5;
int n,m,rt[N];
namespace SGT{
    #define lc (son[p][0])
    #define rc (son[p][1])
    #define mid (l+r>>1)
    int fa[N*30],rk[N*30],son[N*30][2],tot=0;
    inline void build(int&p,int l,int r){
        p=++tot;
        if(l==r){rk[p]=1,fa[p]=l;return;}
        build(lc,l,mid),build(rc,mid+1,r);
    }
    inline void update(int&p,int o,int l,int r,int k,int v){
        p=++tot;
        if(l==r){fa[p]=v,rk[p]=rk[o];return;}
        lc=son[o][0],rc=son[o][1];
        k<=mid?update(lc,son[o][0],l,mid,k,v):update(rc,son[o][1],mid+1,r,k,v);
    }
    inline void modify(int&p,int l,int r,int k){
        if(l==r){++rk[p];return;}
        k<=mid?modify(lc,l,mid,k):modify(rc,mid+1,r,k);
    }
    inline int query(int p,int l,int r,int k){
        if(l==r)return p;
        return k<=mid?query(lc,l,mid,k):query(rc,mid+1,r,k);
    }
};
inline int find(int id,int x){
    int fa=SGT::query(rt[id],1,n,x);
    return x==SGT::fa[fa]?fa:find(id,SGT::fa[fa]);
}
inline void merge(int id,int x,int y){
    int px=find(id,x),py=find(id,y);
    if(px==py)return;
    int rx=SGT::rk[px],ry=SGT::rk[py],fx=SGT::fa[px],fy=SGT::fa[py];
    if(rx<ry)swap(fx,fy),swap(rx,ry);
    SGT::update(rt[id],rt[id-1],1,n,fy,fx);
    if(rx==ry)SGT::modify(rt[id],1,n,fx);
}
int main(){
    n=read(),m=read(),SGT::build(rt[0],1,n);
    for(ri i=1,op,x,y;i<=m;++i){
        op=read(),x=read();
        if(op^2)y=read(),rt[i]=rt[i-1];
        switch(op){
            case 1:merge(i,x,y);break;
            case 2:rt[i]=rt[x];break;
            default:cout<<(find(i,x)==find(i,y))<<'\n';
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值