24.并查集

一、简介

并查集是一种用于管理元素所属集合的数据结构,实现为一个森林,其中每棵树表示一个集合,树中的节点表示对应集合中的元素。

顾名思义,并查集支持两种操作:

  • 合并(Merge):合并两个元素所属集合(合并对应的树)
  • 查询(Find):查询某个元素所属集合(查询对应的树的根节点),这可以用于判断两个元素是否属于同一集合

并查集在经过修改后可以支持单个元素的删除、移动;使用动态开点线段树还可以实现可持久化并查集。并查集的使用范围非常广泛,将作为栈和队列这样的基础数据结构在很多题目当中结合应用。而如 K r u s k a l Kruskal Kruskal算法等也需要借助并查集来实现。

二、基本运用

1.初始化

初始时,每个元素都位于一个单独的集合,表示为一棵只有根结点的树。方便起见,我们将根节点的父亲设为自己。

for(ll i=1;i<=n;i++)
	fa[i]=i;

2.查询与路径压缩

为了确认两个元素是否属于同一集合,我们需要判定他们是否拥有同一个祖先。判断是否拥有同一个祖先是一个经典的问题,我们称之为最近公共祖先问题(LCA),我们在后续会专门讲解此问题。

在并查集这里我们并不需要这么复杂的方式。我们可以简化地判断他们是否拥有一个公共的根结点即可。沿着树向上移动,直至找到根结点。

对于层数较大的树而言,要找到根结点花费的时间将比较长。因为一个结点的从属情况到最后实际上只与根结点有关,所以我们可以采用路径压缩的方式,将结点直接连到根结点以加快后续查询。这个过程可以整合到查询当中。

ll get(ll x)
{
	if(x!=fa[x])
		return fa[x]=get(fa[x]);
	return fa[x];
}

3.合并

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

void merge(ll x,ll y)
{
	ll fx=get(x),fy=get(y);
	fa[fx]=fy;
}

在合并的时候还有一种优化方式,称之为启发式合并。因为哪棵树的根节点作为新树的根节点会影响未来操作的复杂度。我们可以将节点较少或深度较小的树连到另一棵,以免发生退化。

同时采用路径压缩和启发式合并对并查集进行优化的话,每次查询的均摊时间复杂度为 O ( α ( N ) ) O(\alpha(N)) O(α(N)) α ( N ) \alpha(N) α(N)为反阿克曼函数, ∀ N ≤ 2 2 1 0 19729 , α ( N ) < 5 \forall N\leq2^{2^{10^{19729}}},\alpha(N)<5 N221019729,α(N)<5。若只采用一种,则均摊时间复杂度为 O ( l o g N ) O(logN) O(logN)

三、带权并查集

1.简介

如果树边不只是表示两者同属一个集合的关系,还涉及到边权的问题,那么这样的并查集就变成了带权并查集,查询与合并时需要进行的操作都有很多的不同。

2.例题:P1196

(1)题目大意

有一个划分为 N N N列的战场,每列依次编号为 1 , 2 , … , N 1,2,\ldots,N 1,2,,N。有 N N N艘战舰,序号依次为 1 , 2 , … , N 1,2,\ldots,N 1,2,,N,让第 i i i 号战舰处于第 i i i 列。现有 M M M条指令,指令有两种格式:

  1. M i j i i i j j j 是两个整数( 1 ≤ i , j ≤ 30000 1 \le i,j \le 30000 1i,j30000),表示指令涉及的战舰编号。表示让第 i i i 号战舰所在列的全部战舰保持原有序列,接在第 j j j 号战舰所在列的尾部。

  2. C i j i i i j j j 是两个整数( 1 ≤ i , j ≤ 30000 1 \le i,j \le 30000 1i,j30000),表示指令涉及的战舰编号。表示查询第 i i i 号战舰和第 j j j 号战舰是否在同一序列,如果在则需要求出他们之间间隔了多少战舰。

数据范围: N ≤ 30000 , M ≤ 5 × 1 0 5 N\leq30000,M\leq5\times10^5 N30000,M5×105

(2)题目分析

  • 此处涉及到判断是否在同意序列以及合并序列的问题,所以很容易想到并查集来求解
  • 唯一的问题是,我们需要求出两个战舰之间隔了多少战舰
  • 如果我们直接进行路径压缩,所有直接与根相连,则无法得出答案
  • 如果不进行路径压缩,则将边权设置为 1 1 1,两者的距离之差减 1 1 1 就是答案了,但这不满足时间复杂的要求
  • 所以,我们在考虑路径压缩的情况下,新建一个数组 d i s t dist dist d i s t [ x ] dist[x] dist[x] 表示战舰 x x x f a [ x ] fa[x] fa[x] 之间的边权,也就是之间的战舰数量
  • 如此一来,我们需要对合并与查询的代码做相应的修改
ll get(ll x)
{
    if(x==fa[x])
        return fa[x];
    ll y=fa[x];
    fa[x]=get(y);
    dist[x]+=dist[y];
    return fa[x];
}
void merge(ll a,ll b)
{
    a=get(a);b=get(b);
    if(a!=b)
    {
        fa[a]=b;
        dist[a]=size[b];
        size[b]+=size[a];
    }
}

四、作业

P3367 【模板】并查集

P2814 家谱

P2661 [NOIP2015 提高组] 信息传递

P1661 扩散

P1196 [NOI2002] 银河英雄传说

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是50道关于并查集的判断题: 1. 并查集是一种数据结构,用于维护元素分组情况。 (√) 2. 并查集可以用于解决连通性问题。 (√) 3. 并查集只能用于处理无向图,不能处理有向图。 (×) 4. 并查集的时间复杂度为 O(n log n)。 (×) 5. 并查集中每个元素的代表元素相同,当且仅当这些元素在同一个集合中。 (√) 6. 并查集的初始化过程中,每个元素的父节点都指向自身。 (√) 7. 并查集的合并操作可以通过路径压缩优化。 (√) 8. 并查集的查找操作可以通过路径压缩优化。 (√) 9. 并查集中两个元素所在的集合相同,当且仅当它们的根节点相同。 (√) 10. 并查集中元素个数为 n,最多有 n 个集合。 (×) 11. 并查集中每个元素的父节点都是唯一确定的。 (√) 12. 并查集的路径压缩操作会改变每个元素的父节点。 (√) 13. 并查集的合并操作会改变每个元素的父节点。 (√) 14. 并查集的查找操作会改变每个元素的父节点。 (×) 15. 并查集可以用于解决最小生成树问题。 (√) 16. 并查集可以用于解决最短路径问题。 (×) 17. 并查集中每个元素的父节点最多只有一个。 (√) 18. 并查集中每个元素的子节点最多只有一个。 (×) 19. 并查集中每个元素的子节点可以有多个。 (√) 20. 并查集可以用于解决拓扑排序问题。 (×) 21. 并查集可以用于解决连通块问题。 (√) 22. 并查集的合并操作时间复杂度为 O(log n)。 (×) 23. 并查集的查找操作时间复杂度为 O(log n)。 (×) 24. 并查集的初始化时间复杂度为 O(n)。 (√) 25. 并查集的合并操作可以通过按秩合并优化。 (√) 26. 并查集的查找操作可以通过按秩合并优化。 (√) 27. 并查集中每个元素的祖先节点可以有多个。 (×) 28. 并查集可以用于解决区间合并问题。 (×) 29. 并查集可以用于解决最长公共祖先问题。 (×) 30. 并查集可以用于解决最大连通块问题。 (√) 31. 并查集可以用于解决最小连通块问题。 (×) 32. 并查集可以用于解决图的同构问题。 (×) 33. 并查集可以用于解决图的同构问题。 (×) 34. 并查集可以用于解决图的同构问题。 (×) 35. 并查集可以用于解决图的同构问题。 (×) 36. 并查集可以用于解决图的同构问题。 (×) 37. 并查集可以用于解决图的同构问题。 (×) 38. 并查集可以用于解决图的同构问题。 (×) 39. 并查集可以用于解决图的同构问题。 (×) 40. 并查集可以用于解决图的同构问题。 (×) 41. 并查集可以用于解决图的同构问题。 (×) 42. 并查集可以用于解决图的同构问题。 (×) 43. 并查集可以用于解决图的同构问题。 (×) 44. 并查集可以用于解决图的同构问题。 (×) 45. 并查集可以用于解决图的同构问题。 (×) 46. 并查集可以用于解决图的同构问题。 (×) 47. 并查集可以用于解决图的同构问题。 (×) 48. 并查集可以用于解决图的同构问题。 (×) 49. 并查集可以用于解决图的同构问题。 (×) 50. 并查集可以用于解决图的同构问题。 (×)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值