可持久化并查集

Posted mrasd

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了可持久化并查集相关的知识,希望对你有一定的参考价值。

可持久化并查集

题意

如题。

解法

我们考虑用主席树来维护每一个版本中,x的father,因为我们要做到可持久化, 所以我们不能压缩路径(可能吧) ,我们就需要用到启发式合并。每次将深度较浅的合并到深度较大的集合中,并且,如果两个集合深度相同了的话,将其中的一个深度+1。剩下的就是主席树的基本操作了。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <cctype>
#define INF 2139062143
#define MAX 0x7ffffffffffffff
#define del(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
template<typename T>
inline void read(T&x)
{
    x=0;T k=1;char c=getchar();
    while(!isdigit(c)){if(c==‘-‘)k=-1;c=getchar();}
    while(isdigit(c)){x=x*10+c-‘0‘;c=getchar();}x*=k;
}
const int maxn=1e5+5;
struct node{
    int lc,rc,fa,deep;
}T[maxn*40];
int root[maxn*2],sz;
int n,m;

void build(int &x,int l,int r){
    x=++sz;
    if(l==r){
        T[x].fa=l;
        return;
    }
    int mid=(l+r)/2;
    build(T[x].lc,l,mid);
    build(T[x].rc,mid+1,r);
}

void update(int l,int r,int pos,int fa,int &x,int y){
    T[++sz]=T[y],x=sz;
    if(l==r) { T[x].fa=fa;return;}
    int mid=(l+r)/2;
    if(pos<=mid) update(l,mid,pos,fa,T[x].lc,T[y].lc);
    else update(mid+1,r,pos,fa,T[x].rc,T[y].rc);
}

node query(int x,int l,int r,int pos){
    if(l==r) return T[x];
    int mid=(l+r)/2;
    if(pos<=mid) return query(T[x].lc,l,mid,pos);
    else return query(T[x].rc,mid+1,r,pos);
}

void add(int x,int l,int r,int pos){
    if(l==r) { ++T[x].deep;return;}
    int mid=(l+r)/2;
    if(pos<=mid) add(T[x].lc,l,mid,pos);
    else add(T[x].rc,mid+1,r,pos);
}

node find_fa(int x,int pos){
    node k=query(x,1,n,pos);
    if(k.fa==pos) return k;
    return find_fa(x,k.fa);
}

void uni(int &x,int y,int pos1,int pos2){
    x=y;
    node f1=find_fa(x,pos1),f2=find_fa(x,pos2);
    if(f1.fa!=f2.fa){
        if(f1.deep>f2.deep) swap(f1,f2);
        update(1,n,f1.fa,f2.fa,x,y);
        if(f1.deep==f2.deep) add(x,1,n,f2.fa);
    }
}

int main()
{
    read(n),read(m);
    build(root[0],1,n);
    for(int i=1;i<=m;i++){
        int k,x,y;
        read(k);
        if(k==1){
            read(x),read(y);
            uni(root[i],root[i-1],x,y);
        }
        if(k==2){
            read(x);
            root[i]=root[x];
        }
        if(k==3){
            read(x),read(y);
            root[i]=root[i-1];
            node fa1=find_fa(root[i],x),fa2=find_fa(root[i],y);
            if(fa1.fa==fa2.fa) printf("1
");
            else printf("0
");
        }
    }   
    return 0;
}

以上是关于可持久化并查集的主要内容,如果未能解决你的问题,请参考以下文章

[bzoj3673][可持久化并查集 by zky] (rope(可持久化数组)+并查集=可持久化并查集)

可持久化并查集

BZOJ-3673&3674可持久化并查集 可持久化线段树 + 并查集

可持久化4--可持久化并查集

[BZOJ 3673]可持久化并查集 by zky

半可持久化并查集