【模板】并查集
题目描述
如题,现在有一个并查集,你需要完成合并和查询操作。
输入格式
第一行包含两个整数 ,表示共有 个元素和 个操作。
接下来 行,每行包含三个整数 。
当 时,将 与 所在的集合合并。
当 时,输出 与 是否在同一集合内,是的输出
Y ;否则输出 N 。
输出格式
对于每一个 的操作,都有一行输出,每行包含一个大写字母,为 Y 或者 N 。
样例 #1
样例输入 #1
4 7
2 1 2
1 1 2
2 1 2
1 3 4
2 1 4
1 2 3
2 1 4
样例输出 #1
N
Y
N
Y
提示
对于 的数据,,。
对于 的数据,,。
对于 的数据,,,,。
思路
首先,定义一个大小为的数组pre,用于记录每个元素的父节点。init函数用于初始化并查集,使得每个元素的父节点都是自己。
root函数用于查找元素的根节点,即在并查集中寻找所在集合的代表元素。这里采用路径压缩的方法,即在查找过程中,将到根节点的路径上的所有节点的父节点都直接设为根节点,从而优化后续查找效率。
merge函数用于合并两个集合,具体操作是找到两个元素的根节点,如果根节点不同,就将其中一个集合的根节点的父节点设置为另一个集合的根节点,从而实现两个集合的合并。
check函数用于检查两个元素是否在同一集合中,通过比较两个元素的根节点是否相同来判断。如果相同,输出"Y";如果不同,输出"N"。
在main函数中,首先读取元素的数量和操作的数量,然后进行初始化。接下来,根据输入的操作类型,进行合并或者检查操作。如果操作类型为1,执行merge函数合并两个集合;如果操作类型为2,执行check函数检查两个元素是否在同一集合中。
使用路径压缩优化后,代码运行用时大幅度缩短。但是路径压缩会破坏树形结构。
AC代码
#include <iostream>
#define AUTHOR "HEX9CF"
using namespace std;
const int N = 1e5 + 7;
int pre[N];
void init(int x) {
for (int i = 1; i <= x; i++) {
pre[i] = i;
}
}
int root(int x) {
int i = x;
while (pre[i] != i) {
i = pre[i];
}
return pre[x] = i;
}
void merge(int x, int y) {
x = root(x);
y = root(y);
if (x == y) {
return;
}
pre[x] = y;
}
void check(int x, int y) {
x = root(x);
y = root(y);
if (x == y) {
printf("Y\n");
} else {
printf("N\n");
}
}
int main() {
int n, m;
scanf("%d %d", &n, &m);
init(n);
while (m--) {
int z, x, y;
scanf("%d %d %d", &z, &x, &y);
if (z == 1) {
merge(x, y);
} else {
check(x, y);
}
}
return 0;
}