本文最后更新于 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]); }
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[c]=find(a);
|
简直是太巧妙了!
而判定两个人的老大是否相等,只需
就好了。
一些设定:
- 一个人不能有两个老大。
- 当已经有老大的人臣服时,老大也将成为胜利的人的小弟。
代码:
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;
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; for(i=1;i<=m;i++){ cin>>p1>>p2>>p3; if(p1==1) f[find(p2)]=find(p3); else if(find(p2)==find(p3)) printf("Y\n"); else printf("N\n"); } return 0; }
|