0%

ZROI-C-day1

并查集

优化方式

  1. 路径压缩
  2. 按秩合并 (merge时size小的当儿子)

可撤销并查集

路径压缩是无法撤销的。
但按秩合并可以。
所以只写按秩合并就行。记一下 merge 的时候连的哪条边。
时间复杂度 O(nlogn)O(n \log n)

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
30
31
32
33
34
35
36
37
template <const int N> struct dsu
{
int f[N], g[N];
stack<pair<int *, int>> s;
void init(int n)
{
for (int i = 0; i <= n; i++)
f[i] = i, g[i] = 1;
}
int get(int u)
{
return f[u] == u ? u : get(f[u]);
}
bool find(int u, int v)
{
return get(u) == get(v);
}
void merge(int u, int v)
{
u = get(u), v = get(v);
if (u == v)
return;
if (g[u] > g[v])
swap(u, v);
s.push({f + u, f[u]}), f[u] = v;
s.push({g + v, g[v]}), g[v] += g[u];
}
unsigned tag()
{
return s.size();
}
void undo(unsigned tag)
{
while (s.size() > tag)
*s.top().first = s.top().second, s.pop();
}
};

Kruskal 重构树

并查集在合并集合的时候是直接加一条边上去。
考虑另一种做法:找到 u,vu, v 所在树的根节点 u,vu', v',然后新建一个结点 zz作为 u,vu', v' 的父亲。
这样我们就得到了 kruskal 重构树。
原树上的点在重构树上都是叶子结点,并且 kruskal 重构树是一棵二叉树。可以理解为一种特殊的三度化(树转二叉树)

欢迎关注我的其它发布渠道