一般处理的问题
1.将两个集合合并
2.询问两个元素是否在一个集合当中

如果是暴力做法 数组存储每个元素属于哪一个集合
1.
belong[x]=a
if(belong[x]=belong[y]) O(1)
2.如果想合并 极其麻烦 元素多了就寄了

基本原理
用树的形式维护每一个集合 树根的编号就是集合的编号
每个节点存储它的父节点p[x]表示x的父节点
1.
将一棵树插到另一棵树
px是x的集合编号 py是y的集合编号 合并就是p[x]=y

  1. 求某个点属于哪个集合 通过其父节点
    求x的集合编号 while(p[x]!=x) x=p[x]; 路径压缩优化 一旦找到根节点 整个路径上所有结点直接指向根节点
[并查集] [c++]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include<bits/stdc++.h>
using namespace std;
const int N=1000010;
int n,m;
int p[N]; //存父节点

int find(int x) //返回x的祖宗节点+路径压缩
{
if(p[x]==x) return x;//没错 就两行 如果x不是根节点 就让x的父节点等于它的祖宗节点
return p[x]=find(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;
cin>>op>>a>>b;
if(op[0]=='M') p[find(a)]=find(b) //合并操作 让a的祖宗节点的父亲等于b的祖宗节点 相当于插入了
else //判断是否在同一个集合里
{
if(find(a)==find(b)) puts("Yes")
else puts("No")
}
}
}


acwing 837
其实思路十分相近 所谓连通块可以直接用集合来维护 只需模板代码稍作改变
主要问题是怎么维护size 也就是集合里元素数量

[连通块中点的数量] [c++]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include<bits/stdc++.h>
using namespace std;
const int N=1000010;
int n,m;
int p[N],size[N]; //每一个集合里点的数量

int find(int x)
{
if(p[x]==x) return x;
return p[x]=find(p[x])
}

int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++)
{
p[i]=i;
size[i]=1;
}
while(m--)
{
char op[5];
int a,b;
cin>>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);

}
else if(op[1]=='1')
{
cin>>a>>b;
if(find(a)==find(b)) puts("Yes");
else puts("No");
}
else // 问数量
{
cin>>a;
cout<<size[(find(a))];
}
}
}