并查集入门
并查集
并查集是一种数据结构,用于维护一个“森林”,即可以用于反复查找某个节点的父节点或合并任意两颗树。
1. 查找父节点
初始化每个节点的父节点为其自己。
调用 find
函数时,首先特判(if (f[x] == x)
)检查需要 find
的节点是否已经是根节点,如果是便直接返回自己。
简单思路
如果不是根节点则查找此节点父亲的父亲,即为 return find(f[x])
。
但是这样有一个问题,假设这棵树很长很长,如下图:
有 \(n\) 层,那么你需要递归 \(n\) 次才能找到,所需时间很多。
像这样:
这时候我们可以使用路径压缩优化一下。
路径压缩
路径压缩的作用是让这棵树仅有两层:根节点和叶子节点层。
即为将此节点的父亲节点设为此节点的父亲节点的父亲节点的父亲节点的......(直到递归至根节点)。
return f[x] = find(f[x])
路径压缩后的树会转换成大概这种状态:
这样仅需递归较少的层数即可。
2. 合并操作
合并操作就更简单了,直接将被合并的那颗树的根节点的父亲节点设置为合并进去的树的根节点即可。
f[find(y)] = find(x)
如下图所示:
P3367 AC 代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int n, m, f[200005];
int find(int x)
{
if (f[x] == x)
return x;
return f[x] = find(f[x]);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i++)
f[i] = i;
for (int i = 1; i <= m; i++)
{
int z, x, y;
cin >> z >> x >> y;
if (z == 1)
f[find(y)] = find(x);
else if (z == 2)
{
if (find(x) == find(y))
cout << "Y\n";
else
cout << "N\n";
}
}
return 0;
}
作者:George0915,转载请注明原文链接:https://www.cnblogs.com/George222/p/18787678