算法学习笔记(3):带权并查集的实现及其应用
带权并查集
普通的并查集只能维护每个节点所在集合的编号,带权并查集则可以维护集合内任意一点到所在集合根的距离。
简单来说,带权并查集支持如下两种操作:
-
在点
和 之间连一条边权为 的边( 在不同的连通块内)。 -
查询点
与该连通块的根(即并查集的根)的距离。
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]
:点
dis[x]
:点
请一定注意 dis
数组的定义,如果我们要询问 find
函数(由于使用了路径压缩,此时
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)
:在点
这里是带权并查集比较难理解的一部分,配合图片食用更加。
这是初始状态,我们先调用了一次 find(x)
和 find(y)
,
我们的任务是在 f[x]
或 f[y]
都会破坏并查集的结构,因此只能合并
明确一点,根据我的写法,最终集合的根应该为
所以只要在 dis[fx]
的值修改为
例题:给定
解法:把每个约束拆成
对于每个约束
-
若
和 不在同一连通块内,从 向 连一条权为 的边。 -
若
和 在同一连通块内,只要判断 ( 到根路径权值和) 减去 ( 到根路径权值和) 是否为 即可。
解法:对于 M i j
,从 (C i j
,输出
解法:考虑到
如果
-
是同类,则从 向 连一条权为 0 的边。 -
捕食 ,从 向 连一条权为 1 的边。
如果
-
是同类,则 ( 到根权值和) 不等于 ( 到根权值和) 则为假话。 -
捕食 ,则 ( 到根权值和) - ( 到根权值和) 不为 1 则为假话。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通