摘要:
并查集模板题。
题目
一共有 $n$ 个数,编号是 $1∼n$,最开始每个数各自在一个集合中。
现在要进行 $m$ 个操作,操作共有两种:
M a b
,将编号为 $a$ 和 $b$ 的两个数所在的集合合并,如果两个数已经在同一个集合中,则忽略这个操作;Q a b
,询问编号为 $a$ 和 $b$ 的两个数是否在同一个集合中;
输入格式
第一行输入整数 $n$ 和 $m$。
接下来 $m$ 行,每行包含一个操作指令,指令为 M a b
或 Q a b
中的一种。
输出格式
对于每个询问指令 Q a b
,都要输出一个结果,如果 $a$ 和 $b$ 在同一集合内,则输出 Yes
,否则输出 No
。
每个结果占一行。
数据范围
$1≤n,m≤10^5$
输入样例:
4 5
M 1 2
M 3 4
Q 1 2
Q 1 3
Q 3 4
输出样例:
Yes
No
Yes
并查集/Union-Find
并查集用于解决两个不相交集合 Disjoint Set 的合并 Union,以及查询两个数是否在同一集合中 Find 的问题。
并查集可以以 $O(1)$ 的时间复杂度合并两个不相交集合,以及近乎 $O(1)$ 的时间复杂度查询两个数是否在同一集合中。
核心思想:
- 维护一个森林 Forest,森林中每个节点保存该节点的父节点值。每棵树表示一个集合。
- 合并两个集合 Union:找到两个集合所对应的树根节点,将其中一棵树的根节点作为另一棵树根节点的子节点。本质上是合并两颗多叉树。
- 查找两个数是否在同一集合 Find:分别查找两个数对应森林节点的树根节点,判断根节点是否相同。
路径压缩优化 Path Compression:
在实现 Find 时,需要根据当前数在树中自底向上找到父节点直到树根。
可以在这个过程中压缩路径,即,找到根节点后,将路径中的每个节点的父节点指向根节点。
实现:
1 |
|
- 我们令
parent[x] = x
定义x
为根节点。 - 注意在实现
find
函数找根节点时,我们的做法是自底向上递归处理,在递归过程中如果发现当前节点不为根节点的话,就将当前节点的父节点通过递归的方式指向根节点。
原题链接: AcWing 836. 合并集合