朴素并查集
思想:可以将每个集合想像成一颗树,根节点代表这棵树所属的集合
根节点 p[x] = x;
子节点 p[son] = x;
每次合并两个集合就是将一棵树的合并成另一棵树的子树。
查询就是查询根节点是否相同
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
int n, m;
int p[N];
//路径压缩,通过递归和回溯,将集合中每个节点的值都赋值为根节点
int find(int x)
{
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main()
{
cin>>n>>m;
for(int i = 1; i <= n; i++)
{
p[i] = i;
}
while (m -- ){
char op[2];
int a, b;
scanf("%s%d%d", op, &a, &b);
if(op[0] == 'M')
{
p[find(a)] = find(b);
}
else
{
if(find(a) == find(b)) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
}
return 0;
}
维护size的并查集
与朴素并查集不同的地方在于,合并时需要判断不在一个集合才能进行合并操作
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
int n, m;
int p[N];
int _size[N];
//路径压缩
int find(int x)
{
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main()
{
cin>>n>>m;
for(int i = 1; i <= n; i++)
{
p[i] = i;
_size[i] = 1;
}
while (m -- ){
char op[5];
int a, b;
scanf("%s", op);
if(op[0] == 'C')
{
cin>>a>>b;
if(find(a) == find(b)) continue;
_size[find(b)] += _size[find(a)];
p[find(a)] = find(b);
}
if(op[0] == 'Q')
{
if(op[1] == '1')
{
cin>>a>>b;
if(find(a) == find(b)) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
if(op[1] == '2')
{
cin>>a;
cout<<_size[find(a)]<<endl;
}
}
}
return 0;
}
\