ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

并查集学习笔记

2022-08-10 21:02:06  阅读:157  来源: 互联网

标签:int 查集 笔记 学习 fa 集合 root find


很抱歉这篇博客晚来了(该放在Kruskal前面的)......

并查集,故名思意,就是用来高效进行合并、查询集合的数据结构,为了方便,我们可以把每一个结点看成树形结构即可。

1.查询

Q1:我们该如何查询某一个结点在哪一个集合呢?

A1:我们知道如果需要区分开所有集合,就应该用一个代表来表示这个集合,在这里,我们把这个集合的根节点看作那个代表即可。

Q2:我们该如何判断两个结点 \(x,y\) 是否在一个集合呢?

A2:我们可以从 \(x,y\) 不停往上递归,只要遍历到那个根节点代表即可。

Q3:如何递归?

A3:我们设 \(fa_x\) 为 \(x\) 的父亲,然后将根节点 \(root\) 的 \(fa_{root}\) 设为 \(root\) ,然后我们不停往上递归,判断这个结点的 \(fa\) 值是否为本身即可。

code:

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

但是我们发现如果这个集合是一条链的话,如图:img

(图来来自菜鸟

时间复杂度会退化成 \(O(n)\) ,那么这时候我们就要采用路径压缩来做,每做一次,就将 \(fa_x=root\),这样后面继续进行查找时间复杂度就会成为优秀的 \(O(1)\)

code:

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

2.合并

Q1:如何合并 \(x,y\) 两个集合?

A1:将 \(x\) 集合的根节点拉一条边朝向 \(y\) 集合的祖先。

code:

void merge(int x,int y)
{
    fa[find(x)] = find(y);
}

习题

接下来我们通过一些习题来认识一些特殊的并查集

1.P3367 【模板】并查集

普通并查集,套用刚刚的模板即可。

2.P1196 [NOI2002] 银河英雄传说

带权并查集,我们设 \(d_i\) 为 \(i\) 到此集合根节点的距离,由于统计的是边的数量,所以我们最后统计答案的时候要将他变为 \(d_b-d_a-1\)。

(1)查询的变化

当我们没有迭代到根节点的时候,首先弄出根节点 \(root\) ,然后将 \(d_x\) 加上 \(d_{fa_x}\) ,接着再路径压缩

int find(int x)
{
    if(fa[x] != x)
    {
        int root = find(fa[x]);
        d[x] += d[fa[x]];
        fa[x] = root;
    }
    return fa[x];
}

(2)合并的变化

我们再维护一个 \(siz\) 数组,当 \(x\) 和 \(y\) 所在的集合要合并时,先按照模板合并,然后将两个集合的 \(siz\) 值相加,接着 \(d_{rootx} = siz_{rooty}\) 即可(距离 \(rooty\) 的距离为 \(rootx\))

if(fia != fib)
{
    fa[fia] = fib;
    d[fia] = sz[fib];
    sz[fib] += sz[fia];
}

3.P2024 [NOI2001] 食物链

扩展域并查集

我们弄 \(3\) 个集合,对于任意一个结点 \(i\) :

1 \(i\) 表示本身

2 \(i+n\) 表示 \(i\) 的天敌

3 \(i+2n\) 表示 \(i\) 的猎物

后面两个情况直接特判即可,第一种情况:

如果 \(x\) 和 \(y\) 是同类,若 \(x\) 是 \(y\) 的天敌或猎物,那么是假话。
如果 \(x\) 吃 \(y\),若 \(x\) 和 \(y\) 是同类,那么是假话。
如果 \(x\) 吃 \(y\),若 \(x\) 是 \(y\) 的猎物,那么是假话。
如果 \(x\) 吃 \(y\),若 \(y\) 是 \(x\) 的天敌,那么是假话。

代码就不放了。

标签:int,查集,笔记,学习,fa,集合,root,find
来源: https://www.cnblogs.com/ljfyyds/p/16573855.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有