娄卫健 的 主 页
「新生实践课作业」
班级主页 寝室主页

并查集

模板:

int h[N];
for(int i = 0; i < n ; i++)
	h[i] = i; //初始化

int find(int x)//查找+路径压缩
{
	if(h[x] == x) return x;
	return h[x] = find(h[x]);
}

带权并查集

普通的并查集只能维护每个节点所在集合的编号,带权并查集则可以维护集合内任意一点到所在集合根的距离。

简单来说,带权并查集支持如下两种操作:

  • 在点 u 和 v 之间连一条边权为 w 的边(u,v 在不同的连通块内)。
  • 查询点 u 与该连通块的根(即并查集的根)的距离。

find

int find(int x)
{
    if (f[x] == x)
        return x;
    int fa = find(f[x]);//先保存下来父节点
    dis[x] += dis[f[x]];//把到父结点的距离加上父节点到上个结点的距离
    return f[x] = fa;//合并
}

f[x]:点 x 的父亲节点。

dis[x]:点 x 到其 父亲节点(注意不是根节点)的距离。

请一定注意 dis 数组的定义,如果我们要询问 x 到根路径的权值和,只需要先调用一遍 find 函数(由于使用了路径压缩,此时 x 的父亲就为并查集的根)即可。

merge

void merge(int x, int y, int c)
{
    int fx = find(x), fy = find(y);
    if (fx == fy)
        return;
    f[fx] = fy, dis[fx] = c + dis[y] - dis[x];
}

merge(x, y, c):在点 x 和点 y 直接连一条权值为 c 的边,同时将 x 所在的连通块合并到 y 上。

例题:洛谷P1525

扩展域并查集

本人认为可以用带权并查集来替代

但是扩展域并查集是对每个结点i,规定i+n为其对立结点(虚拟的),以此来确定关系。

娄卫健的个人主页(新生实践课)
华中科技大学