可持久化并查集

如果不采用路径压缩而只采用按秩合并,那么并查集的可持久化是比较容易实现的。按秩合并可以保证一棵 $n$ 个节点的树的高度是 $O(\log n)$ 的。

实现方法:
用 $r_v$ 表示 $v$ 所在子树的根。
假设要将点 $u$ 和点 $v$ 所在子树和并(也就是将边 $(u,v)$ 加入图中),那么需要在合并之前记录一下 $r_u, \mathrm{rank}(r_u)$ 和 $r_v, \mathrm{rank}(r_v)$。
要恢复到某个历史版本,就按与加边相反的顺序删边。

const int N = 5e5 + 5;
int par[N];
int rk[N];

int root(int x){
    while(x != par[x]) x = par[x];
    return x;
}

struct his{
    int u, rk1;
    int v, rk2;
};

his unite(int x, int y){
    x = root(x);
    y = root(y);

    his res = {x, rk[x], y, rk[y]};

    if(x == y) return res;
    if(rk[x] > rk[y])
        par[y] = x;
    else{
        par[x] = y;
        if(rk[x] == rk[y])
            ++rk[y];
    }
    return res;
}


void divide(const his &x){
    par[x.u] = x.u;
    par[x.v] = x.v;
    rk[x.u] = x.rk1;
    rk[x.v] = x.rk2;
}

转载于:https://www.cnblogs.com/Patt/p/7856030.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值