并查集学习笔记

并查集

1. 并查集的定义

并查集(DSU)是一种用于维护 不相交集合 的数据结构,主要支持查找和合并两种操作:

  • Find:查询某个元素属于哪个集合
  • Union:将两个元素所在的集合合并

并查集通常用一棵树表示一个集合,根节点就是该集合的代表元
当且仅当两个元素对应的根节点相同时,它们在同一个集合中

2. 并查集的实现

2.1 初始化

初始时每个元素都是一个独立的集合,并通过将父节点指向自己表明自己是根

并查集初始化参考代码

void ini(){
	for(int i=1;i<=n;i++){
		fa[i]=i;
  dep[i]=0; // 树的深度,在启发式合并中用到
}
}

2.2 查找

2.2.1 朴素的查找方式

朴素的查找方式通过一步一步向上跳找根节点,最坏情况下单次查找时间为 \(O(n)\)

并查集朴素查找参考代码

int find(int x){
	while(fa[x]!=x)
  x=fa[x];
return x;
}

朴素查询示意图

朴素查询

2.2.2 路径压缩优化

因为过程中经过的每个元素 都属于该集合 ,所以我们可以将其 直接连到根节点 以加快后续查询,这是并查集的精髓也是 最关键的优化

但是路径压缩也有其局限性,因为在路径压缩后会 丢失部分信息 ,导致并查集 无法回退回以前的状态

并查集路径压缩优化查找参考代码

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

路径压缩示意图

路径压缩

2.3 合并

2.3.1 朴素的合并

要合并两棵树,我们只需要将一棵树的根节点连到另一棵树的根节点即可

并查集朴素合并参考代码

void unio(int x,int y){
	int u=find(x),v=find(y);
if(u==v)
  return ;
fa[u]=v;
return ;
}

并查集合并示意图

合并

2.3.2 启发式合并

合并时,选择哪棵树的根节点作为新树的根节点 会影响树的高度 ,我们可以 将深度较小的树连到另一棵 ,以尽量减少树的高度

在有路径压缩的前提下,启发式合并的效率提高并不多,基本可以省略

并查集启发式合并参考代码

void unio(int x,int y){
	int u=find(x),v=find(y);
if(u==v)
  return ;
if(dep[u]>dep[v])
  fa[v]=u;
else{
		fa[u]=v;
  if(dep[u]==dep[v])
      ++dep[v];
}
return ;
}

2.4 复杂度

可以证明,经过 启发式合并路径压缩 优化后的并查集,单次操作均摊复杂度约为 \(O(\alpha(n))\),其中 \(\alpha(n)\) 是反阿克曼函数,可以近似看作 常数

3. 技巧:扩展域并查集

将每个元素 拆分为多个虚拟节点 ,这些虚拟节点称为 ,每个虚拟节点表示一种可能,身份或关系。因此,扩展域并查集 可以维护更复杂的关系

posted @ 2026-08-20 21:08  Sail-With-Dawn  阅读(11)  评论(0)    收藏  举报