并查集
并查集
一、概念
并查集是一种维护多个集合的数据结构。
并查集支持两种操作:
- unite——合并两个元素所属的集合为同一个集合;
- find——查询某个元素所属的集合,进而可以判断两个元素是否属于同一个集合。
每次操作的平均时间复杂度为 \(O(\alpha(n))\),可以近似为 \(O(1)\)。
注意,并查集不能很好地实现集合的分离,即合并之后就掰不开了。
二、模板
find 操作(使用了路径压缩):
int find(int x){
if(x==f[x])return x;
return f[x]=find(f[x]);
}
unite 操作:
void unite(int x,int y){
f[find(y)]=find(x);
}
三、例题
-
扩展域并查集,也叫种类并查集,是并查集的一个变种,用于维护拥有多种类型元素的合并与查询问题。
这道题就是一道典型的例题。如果用并查集表示监狱,那么考虑对于两个互相连通的节点(即有仇恨关系的两个罪犯),它们一定不能处于同一个监狱中。
对于任意节点
u,我们可以用节点u+n表示节点u的“反节点”,即:若节点v与节点u有仇恨关系,那么节点u与节点v的反节点就可以放在同一个并查集里,节点v与节点u的反节点也同理。这样一做,就导致并查集数组大小必须开到原来的两倍。对于这道题,我们当然要把所有的边权进行排序,优先将仇恨度更大的罪犯们放到两个监狱中,即将仇恨度较大的罪犯对各与对方的反节点放到同一个并查集中。
合并过程中,如果发现所要分开放的两个罪犯已经在同一个并查集中,那么说明上述情况导致这两个罪犯不得不被放在一个监狱中,即这两个罪犯一定会爆发矛盾,输出这对罪犯的边权即可。
-
构造每一个节点的反节点,如果两个节点是朋友,那么这两个节点互相合并,它们的反节点也互相合并;反之,则互相合并对方的反节点。
寻找
1~n中的并查集根节点,统计数目即为答案。 -
如果两个洞相交或相切,就把它们放入一个并查集。进而一个并查集代表着一块连通的空洞。
那么我们只需要判断每一条通道是否与顶部和底部相连即可。
然后需要用到一个数学原理:如果两球半径之和大于或等于两球球心距离,那么两球能相切或相交。使用空间坐标系内的两点间距离公式计算距离,并以此为判断逻辑,将每个球按照上述规则扔到并查集里即可。
-
要让同学不抗议,那么可以将所有实力相当的同学扔入一个并查集。进而对于一个并查集内的所有元素,要么同时被选,要么同时不被选。
然后把每个连通块当作一个物品,其价值和体积均为其元素个数,跑 0-1 背包即可。

浙公网安备 33010602011771号