并查集模板

本文最后更新于 2024年5月2日 上午

并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中

模板题

P3367 【模板】并查集

(摘自洛谷大佬huangzirui)

关于并查集和路径压缩:

现在我们假定 f[i] 表示第 i 个人的老大是谁。

现在我们有甲,乙,丙三个人(分别用 a, b, c 表示)

假设甲和乙打架了,甲做了丙的小弟。则有 f[a]=b

后来甲打赢了丙

那么丙就是甲的小弟了。有 f[c]=a

但是如果我们这样表示,丙不能直接知道甲,容易自己人打自己人

所以,我们必须直接让丙的大哥变成最大的老大。

定义函数 find

1
2
3
4
5
6
7
int find(int k){
if(f[k]==k)return k;
return find(f[k]);
}//find 函数可以直接找到最大的老大

f[c]=find(a);
//丙的老大是甲

这时,因为我们要路过他所有的上级,我们也可以顺便使途中经过的人的大哥也变成老大。

1
2
3
4
5
6
7
8
9
10
11
12
//路径压缩
int find(int k){
if(f[k]==k)return k;
return f[k]=find(f[k]);
/*
即:
f[k]=find(f[k]);
return f[k];
*/
}

f[c]=find(a);

简直是太巧妙了!

而判定两个人的老大是否相等,只需

1
if(find(a)==find(b))

就好了。

一些设定:

  • 一个人不能有两个老大。
  • 当已经有老大的人臣服时,老大也将成为胜利的人的小弟。

代码:

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
#include<bits/stdc++.h>
using namespace std;
int i,j,k,n,m,s,ans,f[10010],p1,p2,p3;
//f[i]表示i的集合名
int find(int k){
//路径压缩
if(f[k]==k)return k;
return f[k]=find(f[k]);
}
int main()
{
cin>>n>>m;
for(i=1;i<=n;i++)
f[i]=i;//初始化i的老大为自己
for(i=1;i<=m;i++){
cin>>p1>>p2>>p3;
if(p1==1)
f[find(p2)]=find(p3);
//p3打赢了p2
else
if(find(p2)==find(p3))
//是否是一伙的
printf("Y\n");
else
printf("N\n");
}
return 0;
}

并查集模板
https://bobrocket.github.io/2023/03/03/并查集模板/
作者
软核
发布于
2023年3月3日
许可协议