Union-Find
graph BT 2((2)) --"fa[2]"--> 1((1)) 3((3)) --"fa[3]"--> 1 4((4)) --"fa[4]"--> 3 5((5)) --"fa[5]"--> 3 8((8)) --> 7((7)) 7 --> 6((6))overview
Section titled “overview”它可以高效地解决以下问题:
- 合并 (Union) :将两个集合合并为一个集合 (合并对应的树)。
- 查询 (Find) :查询某个元素属于哪个集合 (通常通过找到集合的代表元素, 即根节点)。
并查集的核心思想是用一个数组表示集合,通过路径压缩和按秩合并优化,使得查询和合并操作的时间复杂度接近常数 (摊还时间复杂度为
通常在判断是否可达, 连通性问题时 进行查询, 如需要判断 u, v 是否属于同一个集合, 则可以判断 find(u) == find(v)
# 例如 fa[4] = 3 -> fa[3] = 1 -> fa[1] = 1def find(x): if fa[x] == x: return x return find(fa[x])# or 如下写法def find(x): return x if fa[x] == x else find(fa[x])
find = lambda x: x if fa[x] == x else find(fa[x])有时需要将两个集合合并(例如两个家庭结婚), 例如将 u, v 合并为同一个集合, 则可以将 u 的根节点的父节点设为 v 的根节点
graph BT 1 --> 6 2((2)) --> 1((1)) 3((3)) --> 1 4((4)) --> 3 5((5)) --> 3 8((8)) --> 7((7)) 7 --> 6((6))def union(x, y): x = find(x) y = find(y) if x != y: fa[x] = y# ordef union(x, y): if find(x) != find(y): fa[find(x)] = find(y)[!info]- python 的
=操作是 引用模型 (Reference Model)a = b{:py}是将 a 指向 b# 赋值语法: 变量 = 字面量; 实际上是b = [1, 2, 3]# 引用语法: 变量 = 变量a = ba[0] = 4print(b) # [4, 2, 3]
flowchart LR subgraph 第一阶段 2((2)) --> 1((1)) 3((3)) --> 1 4((4)) --> 3 5((5)) --> 3 end
subgraph 第二阶段 2.2((2)) --> 2.1((1)) 2.3((3)) --> 2.1 2.4((4)) --> 2.1 2.5((5)) --> 2.1 end
第一阶段 --路径压缩--> 第二阶段路径压缩是指在查找过程中, 将访问过的节点的父节点直接指向根节点, 以减少树的高度, 提高查询效率
def find(x): if fa[x] == x: # 如果 x 是根节点 return x fa[x] = find(fa[x]) # 路径压缩 return fa[x]我们通过对查询操作引入路径压缩, 可以对比 find
fa = list(range(n)) #def find(x): if fa[x] == x: return x fa[x] = find(fa[x]) # 路径压缩 return fa[x]def union(x, y): if find(x) != find(y): fa[find(x)] = find(y)可以不用考虑迭代模板, 一般不会爆栈的
fa = list(range(n)) #def find(x): root = x while fa[root] != root: root = fa[root] while fa[x] != x: # 路径压缩 fa[x], x = root, fa[x] return rootdef union(x, y): root_x = find(x) root_y = find(y) if root_x != root_y: fa[root_x] = root_y