可持久化并查集

数据结构 可持久化并查集

最近开始研究“可持久化”,顺便练一练

普通并查集

事实上,总结一下普通并查集,无非就是利用fa[]数组来记录节点间的联系。

可持久化并查集

将并查集可持久化,本质上就是可持久化一个数组。而可持久化数组正是万恶之源——主席树。通过主席树来可持久化fa[]数组即可

但是在尝试路径压缩的时候出了点问题。众所周知,主席树每一次只增加一条链,也就是说只能对原数组进行一次更改。而路径压缩就可能导致一条路径上很多点都被更改,需要大量新建链,丧失了主席树的灵魂

因此,我们改而采用“按秩合并”

按秩合并的思路很简单,将深度小的子树接到深度大的子树上。这么做可以保证只修改一个点的同时,将复杂度优化到\(O(\log n)\)

具体而言

合并时保证dep_a\(\geq\)dep_b

将fa[b]改为fa_a

倘若dep_a=dep_b,那么dep[fa_a]++

就是酱紫,例题好像只有作为暴力解法的[NOI2018]归程

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int MAXD=1e8+5,MAXN=4e5+5;

struct data{
    int lson,rson,val;
}node[MAXD];

int n,m,tot;
int root_fa[MAXN],root_dep[MAXN];

inline int read();
void build_fa(int,int,int);
void build_dep(int,int,int);
void create(int);
void copy(int,int);
void modify(int,int,int,int,int,int);
int query(int,int,int,int);
int find(int,int);
bool check(int,int,int);

void debug(int);

int main(){
    #ifndef ONLINE_JUDGE
    freopen("test.in","r",stdin);
    #endif

    n=read(); m=read();

    root_fa[0]=++tot; build_fa(root_fa[0],1,n);
    root_dep[0]=++tot; build_dep(root_dep[0],1,n);

    for(int i=1;i<=m;++i){
        int type,a,b,k; type=read();
        int fa_a,fa_b,dep_a,dep_b;
        create(i);
        switch(type){
            case 1:
            a=read(); b=read();
            fa_a=find(a,i-1); fa_b=find(b,i-1);
            if(fa_a==fa_b) {copy(i-1,i); break;}
            dep_a=query(root_dep[i-1],1,n,fa_a);
            dep_b=query(root_dep[i-1],1,n,fa_b);
            if(dep_a<dep_b) {swap(a,b); swap(fa_a,fa_b); swap(dep_a,dep_b);}
            modify(root_fa[i-1],root_fa[i],1,n,fa_b,fa_a);
            if(dep_a==dep_b) modify(root_dep[i-1],root_dep[i],1,n,fa_a,dep_a+1);
            else modify(root_dep[i-1],root_dep[i],1,n,fa_a,dep_a);
            break;

            case 2:
            k=read();
            copy(k,i);
            break;

            case 3:
            copy(i-1,i);
            a=read(); b=read();
            printf("%d\n",check(a,b,i));
            break;
        }
    }

    return 0;
}

inline int read(){
    char tmp=getchar(); int sum=0; bool flag=false;
    while(tmp<'0'||tmp>'9'){
        if(tmp=='-') flag=true;
        tmp=getchar();
    }
    while(tmp>='0'&&tmp<='9'){
        sum=(sum<<1)+(sum<<3)+tmp-'0';
        tmp=getchar();
    }
    return flag?-sum:sum;
}

void build_fa(int p,int l,int r){
    if(l==r) {node[p].val=l; return;}
    int mid=(l+r)>>1;
    node[p].lson=++tot; build_fa(node[p].lson,l,mid);
    node[p].rson=++tot; build_fa(node[p].rson,mid+1,r);
}

void build_dep(int p,int l,int r){
    if(l==r) {node[p].val=1; return;}
    int mid=(l+r)>>1;
    node[p].lson=++tot; build_dep(node[p].lson,l,mid);
    node[p].rson=++tot; build_dep(node[p].rson,mid+1,r);
}

void create(int k){
    root_fa[k]=++tot; root_dep[k]=++tot;
}

void copy(int a,int b){
    int ra=root_fa[a]; int rb=root_fa[b];
    node[rb].lson=node[ra].lson;
    node[rb].rson=node[ra].rson;
    ra=root_dep[a]; rb=root_dep[b];
    node[rb].lson=node[ra].lson;
    node[rb].rson=node[ra].rson;
}

void modify(int pre,int p,int l,int r,int pos,int k){
    node[p].lson=node[pre].lson;
    node[p].rson=node[pre].rson;

    if(l==r) {node[p].val=k; return;}

    int mid=(l+r)>>1;
    if(pos<=mid) {node[p].lson=++tot; modify(node[pre].lson,node[p].lson,l,mid,pos,k);}
    if(mid+1<=pos) {node[p].rson=++tot; modify(node[pre].rson,node[p].rson,mid+1,r,pos,k);}
}

int query(int p,int l,int r,int k){
    if(l==r) return node[p].val;
    int mid=(l+r)>>1;
    if(k<=mid) return query(node[p].lson,l,mid,k);
    if(mid+1<=k) return query(node[p].rson,mid+1,r,k);
}

int find(int u,int ver){
    int v=query(root_fa[ver],1,n,u);
    while(u!=v) {u=v; v=query(root_fa[ver],1,n,u);}
    return v;
}

bool check(int a,int b,int ver){
    return find(a,ver)==find(b,ver);
}

void debug(int ver){
    cout<<"This is version No."<<ver<<endl;
    for(int i=1;i<=n;++i){
        int fa=find(i,ver);
        cout<<fa<<" "<<query(root_dep[ver],1,n,fa)<<endl;
    }
    cout<<endl;
}

原文链接: https://www.cnblogs.com/ticmis/p/13210584.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    可持久化并查集

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/360579

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年3月2日 下午1:21
下一篇 2023年3月2日 下午1:22

相关推荐