加权并查集--食物链

食物链Acwing

p:储存下标的根节点是什么, 当输入一个x的时候, px = find(x),先找到x的根节点,在find函数里已经将x归到了它的根树上了,(往上递归直至一个根返回本身)

d[x]:表示x到其父节点的距离,不是根节点!!!

根节点指祖宗,最上方的, 一个集合里面只有一个;

    父节点指调用p的表示,仅为上一层的)

怎么理解find函数???

find函数有两个作用:①路径压缩(找x的根节点) ②更新权值d[x]

·为什么要先  t = find(p[x])?

关键就是既要先执行find(p[x]),又要让d[x] += d[p[x]]中p[x]的值保持不变
递归 find(f[x])的过程就是路径压缩

我们来看一下如果不这样做,

int find(int x)

{
    if (p[x] != x)
    { 
        d[x] += d[p[x]]; //这里的d[p[x]]只是x到父节点的距离,不是到根节点的距离

        p[x] = find(p[x]);
    }
    return p[x];
}

我们发现既要让d[p[x]]正确找到他到根节点的距离, 又要让p[x]暂时不变,否则d[x]加的就不是父节点到根节点的距离了,而是根节点到根节点的距离。

既要?又要? 令人头痛。。。

因此,我们优雅的 暂存 t = find(p[x]), d更新了,p也没变

举个栗子::
假设有一棵树 a -> b -> c -> d, 根节点为 d。d[b]一开始等于 b、c 之间的距离,再执行完路径压缩命令之后,d[b] 等于b、d之间的距离。 d[a] += d[b]: 为了确保d[a]等于 节点a、d的距离,d[b]必须等于b 、d的距离,所以要先调用find(b)更新d[b], 同时p[x] = find(b)会改变p[x]的值,结果就会变成d[a] += d[d],所以先用一个变量把p[a]的值存起来。 关键就是既要先执行find(p[x]), 又要让d[x] += d[p[x]]中p[x]的值保持不变

这样我们就能全面的理解这段代码了。

先调用再递归

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

手动模拟find

路径压缩后

根据权值取模3 就很好判断关系了

https://www.acwing.com/activity/content/code/content/9126551/

<think>嗯,用户想了解加权并查集的概念、实现方法和应用场景。首先,我得回忆一下并查集的基本结构。并查集主要用于处理不相交集合的合并与查询问题,比如动态连通性问题。普通的并查集有Quick Find和Quick Union两种方法,但可能效率不够高。 加权并查集,应该是在合并的时候进行优化,避免树结构过深。记得有两种优化方法,一种是按秩合并(weighted union),另一种是路径压缩(path compression)。用户提到的加权并查集可能指的是前者,也就是在合并时,总是将较小的树连接到较大的树上,这样可以减少查找时的路径长度。 接下来要组织回答的结构。首先解释概念,然后讲实现方法,再讨论应用场景。需要注意用户要求用中文回答,并且数学公式要用$...$格式。比如,在解释树的结构时,可能需要用数组表示父节点和权重,例如父数组parent[i]表示i的父节点,size[i]表示以i为根的树的大小。 实现部分需要分步骤,比如初始化、查找根节点、合并两个集合。其中查找根节点可能需要路径压缩,而合并时比较两个根的大小,将较小的树合并到较大的树上,同时更新size数组。代码示例的话,可能需要用Python或者Java,但用户给的示例是Python,所以用Python更合适。 应用场景方面,动态连通性是最典型的,比如网络连接、社交网络的朋友关系。还有Kruskal算法中的环检测,迷宫生成问题。这些都需要并查集来高效管理集合的合并与查询。 还要记得生成相关问题,比如优化方法、时间复杂度、与其他数据结构的对比。引用部分要正确标注,比如动态连通性问题引用到给定的引用[1]和[2],可能还需要检查引用内容是否符合上下文。 在写作过程中要确保LaTeX语法正确,例如变量用$i$,父数组用$\text{parent}[i]$,公式如时间复杂度$O(\alpha(n))$。同时独立公式要用$$...$$,比如路径压缩后的树高变化可能需要公式,但暂时想不到具体的,可能不需要。 最后检查是否符合所有系统级指令,尤其是格式要求和引用标识的位置。确保回答结构清晰,分点明确,代码正确,问题相关且有意义。</think>### 加权并查集(Weighted Union-Find)详解 #### 一、概念与核心思想 加权并查集是一种优化**并查集(Union-Find)**的数据结构,主要用于高效管理**动态连通性问题**[^2]。其核心优化点在于: 1. **按秩合并(Weighted Union)**:合并两棵树时,将较小树的根节点连接到较大树的根节点,避免树高过度增长; 2. **路径压缩(Path Compression)**:在查找根节点时,将路径上的节点直接连接到根节点,缩短后续查找路径。 通过这两项优化,单次操作的时间复杂度可降低至$O(\alpha(n))$,其中$\alpha(n)$为反阿克曼函数,实际应用中近似常数[^1]。 --- #### 二、实现方法 ##### 1. 数据结构 - **父节点数组** $\text{parent}[i]$:存储元素$i$的父节点 - **权重数组** $\text{size}[i]$:仅当$i$为根节点时有效,表示以$i$为根的子树大小 ##### 2. 关键操作 **初始化**: ```python class WeightedUnionFind: def __init__(self, n): self.parent = list(range(n)) self.size = [1] * n ``` **查找根节点(含路径压缩)**: ```python def find(self, x): while self.parent[x] != x: self.parent[x] = self.parent[self.parent[x]] # 路径压缩 x = self.parent[x] return x ``` **合并集合(按秩合并)**: ```python def union(self, x, y): root_x = self.find(x) root_y = self.find(y) if root_x == root_y: return if self.size[root_x] < self.size[root_y]: self.parent[root_x] = root_y self.size[root_y] += self.size[root_x] else: self.parent[root_y] = root_x self.size[root_x] += self.size[root_y] ``` --- #### 三、应用场景 1. **动态连通性问题** 实时判断网络中的节点连通性(如社交网络好友关系) 2. **Kruskal最小生成树算法** 检测图中添加边后是否形成环 3. **迷宫生成问题** 通过合并相邻单元格生成随机迷宫 4. **图像处理** 在连通区域标记(Connected Component Labeling)中快速合并像素区域[^3] --- #### 四、性能分析 | 操作 | 时间复杂度 | |--------------|-----------------| | 初始化 | $O(n)$ | | `find` | $O(\alpha(n))$ | | `union` | $O(\alpha(n))$ | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值