可撤销并查集

可以支持撤销上一次操作的并查集。

首先一个很重要的前提是,如果我们需要指定哪一个块作为根,是没法可撤销的。

因为它的大致思想是,直接启发式合并,不使用路径压缩,然后记录一下版本值以达到回退的目的。

假设启发式合并中被 Merge 的是 \(v\),那么会改变的数只有 \(siz(ru), pa(rv)\)

我们直接记录一下版本值,每次回退就行了,几乎没有技术含量。

Code
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
struct Dsu {
    int pa[si], siz[si];
    std::vector<std::pair<int&, int>> hp, hs;
    void init(int n) { 
        hp.clear(), hs.clear();
        for(int i = 0; i <= n; ++i) 
            pa[i] = i, siz[i] = 1; 
    }
    int root(int x) {
        if(pa[x] != x)
            return root(pa[x]);
        return pa[x];
    }
    void Merge(int u, int v) {
        int ru = root(u), rv = root(v);
        if(ru == rv) return;
        if(siz[ru] < siz[rv]) swap(ru, rv), swap(u, v);
        hp.push_back(make_pair(pa[rv], pa[rv]));
        hs.push_back(make_pair(siz[ru], siz[ru]));
        siz[ru] += siz[rv], pa[rv] = ru;
    }
    void rollBack(int ver) {
        while((int)hp.size() > ver) {
            hp.back().first = hp.back().second;
            hs.back().first = hs.back().second;
            hp.pop_back(), hs.pop_back();
        }
    }
} dsu;

最后更新: June 30, 2024