并查集

并查集

一、概念

并查集是一种维护多个集合的数据结构。

并查集支持两种操作:

  • unite——合并两个元素所属的集合为同一个集合;
  • find——查询某个元素所属的集合,进而可以判断两个元素是否属于同一个集合。

每次操作的平均时间复杂度为 \(O(\alpha(n))\),可以近似为 \(O(1)\)

注意,并查集不能很好地实现集合的分离,即合并之后就掰不开了。

二、模板

P1551

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);
}

三、例题

  • P1525 [NOIP 2010 提高组] 关押罪犯

    扩展域并查集,也叫种类并查集,是并查集的一个变种,用于维护拥有多种类型元素的合并与查询问题。

    这道题就是一道典型的例题。如果用并查集表示监狱,那么考虑对于两个互相连通的节点(即有仇恨关系的两个罪犯),它们一定不能处于同一个监狱中。

    对于任意节点 u,我们可以用节点 u+n 表示节点 u 的“反节点”,即:若节点 v 与节点 u 有仇恨关系,那么节点 u 与节点 v 的反节点就可以放在同一个并查集里,节点 v 与节点 u 的反节点也同理。这样一做,就导致并查集数组大小必须开到原来的两倍。

    对于这道题,我们当然要把所有的边权进行排序,优先将仇恨度更大的罪犯们放到两个监狱中,即将仇恨度较大的罪犯对各与对方的反节点放到同一个并查集中。

    合并过程中,如果发现所要分开放的两个罪犯已经在同一个并查集中,那么说明上述情况导致这两个罪犯不得不被放在一个监狱中,即这两个罪犯一定会爆发矛盾,输出这对罪犯的边权即可。

  • P1892 [BalticOI 2003] 团伙

    构造每一个节点的反节点,如果两个节点是朋友,那么这两个节点互相合并,它们的反节点也互相合并;反之,则互相合并对方的反节点。

    寻找 1~n 中的并查集根节点,统计数目即为答案。

  • P3958 [NOIP 2017 提高组] 奶酪

    如果两个洞相交或相切,就把它们放入一个并查集。进而一个并查集代表着一块连通的空洞。

    那么我们只需要判断每一条通道是否与顶部和底部相连即可。

    然后需要用到一个数学原理:如果两球半径之和大于或等于两球球心距离,那么两球能相切或相交。使用空间坐标系内的两点间距离公式计算距离,并以此为判断逻辑,将每个球按照上述规则扔到并查集里即可。

  • P2170 选学霸

    要让同学不抗议,那么可以将所有实力相当的同学扔入一个并查集。进而对于一个并查集内的所有元素,要么同时被选,要么同时不被选。

    然后把每个连通块当作一个物品,其价值和体积均为其元素个数,跑 0-1 背包即可。

posted @ 2025-10-31 14:48  L-Coding  阅读(5)  评论(0)    收藏  举报