并查集学习笔记
并查集
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. 技巧:扩展域并查集
将每个元素 拆分为多个虚拟节点 ,这些虚拟节点称为 域,每个虚拟节点表示一种可能,身份或关系。因此,扩展域并查集 可以维护更复杂的关系

浙公网安备 33010602011771号