并查集
并查集
并查集其实解决的内容就是类似于集合合并的问题,然而如果用普通的数组去储存一个集合若数据量大,不仅调用时占用内存空间大,而且不便于插入或查询操作,因此引入并查集可以很好的解决这点。
功能
1.将两个集合合并
2.询问两个元素是否再一个集合当中
思路
理解这个问题就需要把集合给看成一个树,然后这个树的树根就代表这个集合。当想询问其中一个节点时,我们只要访问这个节点father,然后再找这个father的grandfather直到到树根,就能确定这个点的树根。
1 |
|
合并两个集合
合并集合只需要将其中一个集合的树根的编号改成另一个集合的根。
1 |
|
(俗称:给x的祖宗又认了一个爹)
路径压缩
当你找到这个节点的根节点时,就把这些节点的父亲全部变成根节点的编号,也就是让这些节点全部指向根节点。当实现了这个操作后,其查询操作直接将时间复杂度变成O(1)。
1 |
|
例题
1.合并集合
一共有 n𝑛 个数,编号是 1∼n1∼𝑛,最开始每个数各自在一个集合中。
现在要进行 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≤1051≤𝑛,𝑚≤105
输入样例:
1 |
|
输出样例:
1 |
|
题解
1 |
|
2.合并根
题目描述
w 星球的一个种植园,被分成 m×n 个小格子(东西方向 m 行,南北方向 n 列)。每个格子里种了一株合根植物。
这种植物有个特点,它的根可能会沿着南北或东西方向伸展,从而与另一个格子的植物合成为一体。
如果我们告诉你哪些小格子间出现了连根现象,你能说出这个园中一共有多少株合根植物吗?
输入格式
第一行,两个整数 m,n,用空格分开,表示格子的行数、列数(1<m,n<1000)。
接下来一行,一个整数 k,表示下面还有 k 行数据(0<k<1e5)。
接下来 k 行,每行两个整数 a,b,表示编号为 a 的小格子和编号为 b 的小格子合根了。
格子的编号一行一行,从上到下,从左到右编号。
比如:5×4 的小格子,编号:
1 |
|
输出格式
一行一个整数,表示答案
输入样例
1 |
|
输出样例
1 |
|
题解:
1 |
|
这题使用并查集解题,核心主要两个步骤:寻找该元素的根、合并两个集合
然后最后判断是用if(i==p[i])来判断这里的根有几个,因为我们知道只有p[x]==x时,才是这个树的根(因为在数组上理解就是所有的数字比如:[-1,1,2,3,4] —> [ -1,4,2,1,3],我们可以发现数组的顺序表示数字,而对应上面的数字就是其根的索引,在并查集的操作下只有根节点是i==p[i],因此我们也可以将其作为判断几个集合的依据)。