[数据结构]并查集

定义

并查集(Disjoint-Set)是一种可以动态维护若干个不重叠的集合,并支持合并和查询的数据结构,详细的说,并查集基本包括两个操作

  • Get 查询一个元素属于哪一个集合
  • Merge 把两个集合合并为一个大集合

解释

相信大多数人看了上面的官方语言都满头雾水,其实为了实现这种数据结构,我们用一个固定的元素来代表某个集合,对于一些归属关系,我们则可以用一个树形结构来存储每个集合,树上的每个节点代表每个元素,树根就是这个集合的代表元素。

为便于理解,做个形象的比喻,将每个节点比作许多人,节点所属的集合根节点的代表元素就是它的祖先,为了区分这些人,我们只需要知道每个人的祖先是谁即可,不用知道他们之间的具体关系不必清楚,因为我们要做的只是区分这些人,也就是这些元素。

因此,我们在执行get操作时,把每个访问过的节点都直接指向根节点,这种优化方法被称为路径压缩

在基本代码中,我们通常会用到这种优化方法,下面是基本代码:

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

其中fa[x]数组存储的是x节点的祖先

例题:

边带权

由于并查集的特殊结构,我们可以将路径压缩的并查集看做是一棵只有两层的树,我们可以在书中的每一条边上记录一个权值,维护一个数组val,用val[x]保存节点x到fa[x]两个节点之间的权值,在每次路径压缩时去更新访问过节点的val值,这就是所谓的边带权的并查集。

int find(int x)
{
	if(x==fa[x]) return x;
	int root=find(fa[x]);
	val[x]=max(val[fa[x]],val[x]);
	return fa[x]=root;
} 

例题:

扩展域

对于两两不同的节点,他们可能存在不同的关系,这时,使用只能传递单一关系的并查集似乎不太实用,我们可以向原先存储关系的fa数组向后延伸n位,前一部分表示朋友关系,后一部分则表示敌人关系

对于两个元素(x,y),若他们是朋友,则只需merge(x,y),若他们是敌人,则merge(x+n,y),merge(y+n,x)。其中merge表示关系的传递(将x的祖先认为是y的祖先)。

当然,在许多题目中,关系很有可能不止有一种两种,读者们随机应变,向后酌情延伸即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值