可持久化线段树维护启发式合并的可持久化并查集

BZOJ 3673: 可持久化并查集

n个集合 m个操作
操作:
1 a b 合并a,b所在集合
2 k 回到第k次操作之后的状态(查询算作操作)
3 a b 询问a,b是否属于同一集合,是则输出1否则输出0

0<n,m<=2*10^4

题目链接

偶然看到这个数据结构,发现挺简单的,前提是会可持久化线段树,可持久化并查集可以说是可持久化线段树的应用。

并查集维护的是一个父节点指针数组,附带的有时又要维护秩之类的。实习可持久化,我们可以维护多个数组。这样空间肯定是会爆的。那么我们如果直接用主席树维护数组呢。改父亲结点,变成了单点更新。操作回滚变成了普通的主席树回滚。合并,如果不考虑压缩路径直接合并即可。由于主席树中压缩路径不方便回滚(个人感觉)。看了看大牛门的写法,大都是启发式合并,也就是(秩)。到此可持久化线段树可持久化数组可持久化并查集

看不懂的建议先学个前置技能。并查集的启发式合并,和主席树。

/**************************************************************
    Problem: 3673
    User: Q1143316492
    Language: C++
    Result: Accepted
    Time:64 ms
    Memory:64576 kb
****************************************************************/
 
/**
 * BZOJ 3673 可持久化线段树 维护启发式合并的可持久化并查集
 */
//#pragma GCC optimize(2)
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdlib>
#include <map>
#include <set>
 
using namespace std;
typedef long long LL;
const int INF = 0x3F3F3F3F;
const int INT_MAX = 0x7FFFFFFF;
const LL LLINF = 0x3F3F3F3F3F3F3F3F;
const double PI = acos(-1);
const int MAXN = 2e5 + 10;
const int MAXM = 1e6 + 10;
 
struct Node {
    int l, r, faz, rank;
} tree[MAXN * 20];
 
int n, m, root[MAXN], tot;
 
int build(int l, int r) {
    int now = ++tot;
    if(l == r) {
        tree[now].faz = l;
        tree[now].rank = 0;
        return now;
    }
    int mid = (l + r) >> 1;
    tree[now].l = build(l, mid);
    tree[now].r = build(mid + 1, r);
    return now;
}
 
int query(int rt, int l, int r, int x) {
    if(l == r) {
        return rt;
    }
    int mid = (l + r) >> 1;
    if(x <= mid) {
        return query(tree[rt].l, l, mid, x);
    } else {
        return query(tree[rt].r, mid + 1, r, x);
    }
}
 
int find_root(int rt, int x) {
    int y = query(rt, 1, n, x);
    if(x == tree[y].faz) {
        return y;
    }
    return find_root(rt, tree[y].faz);
}
 
int update(int rt, int l, int r, int pos, int val) {
    int now = ++tot;
    tree[now] = tree[rt];
    if(l == r) {
        tree[now].faz = val;
        tree[now].rank = tree[rt].rank;
        return now;
    }
    int mid = (l + r) >> 1;
    if(pos <= mid) {
        tree[now].l = update(tree[now].l, l, mid, pos, val);
    } else {
        tree[now].r = update(tree[now].r, mid + 1, r, pos, val);
    }
    return now;
}
 
void add(int now, int l, int r, int pos) {
    if(l == r) {
        tree[now].rank++;
        return ;
    }
    int mid = (l + r) >> 1;
    if(pos <= mid) {
        add(tree[now].l, l, mid, pos);
    } else {
        add(tree[now].r, mid + 1, r, pos);
    }
}
 
int main() {
 
    while(~scanf("%d %d", &n, &m)) {
        tot = 0;
        root[0] = build(1, n);
        for(int i = 1; i <= m; i++ ) {
            int opt;
            scanf("%d", &opt);
            if(opt == 1) {
                int a, b;
                scanf("%d %d", &a, &b);
                root[i] = root[i - 1];
                int x = find_root(root[i], a);
                int y = find_root(root[i], b);
                if(tree[x].faz == tree[y].faz) {
                    continue;
                }
                if(tree[x].rank > tree[y].rank) {
                    swap(x, y);
                }
                root[i] = update(root[i - 1], 1, n, tree[x].faz, tree[y].faz);
                if(tree[x].rank == tree[y].rank) {
                    add(root[i], 1, n, tree[y].faz);
                }
            } else if(opt == 2) {
                int k;
                scanf("%d", &k);
                root[i] = root[k];                
            } else if(opt == 3) {
                int a, b;
                scanf("%d %d", &a, &b);
                root[i] = root[i - 1];
                a = find_root(root[i], a);
                b = find_root(root[i], b);
                if(tree[a].faz == tree[b].faz) {
                    puts("1");
                } else {
                    puts("0");
                }
            }
        }
    }
 
    return 0;
}
原文地址:https://www.cnblogs.com/Q1143316492/p/9309963.html