C++ 中的重-轻分解2025 年 3 月 19 日 | 阅读 12 分钟 重轻分解 (Heavy-light decomposition, HLD) 是一种有价值的(且广为人知)的方法,常用于竞赛编程和算法构建中,用于优化树的查询。这是因为树本质上更难处理,尤其是在程序需要处理大量查询或修改时。最基本的测试,例如轴向查询,涉及沿着最少边数的两个节点之间值的求和、最大值或最小值查找,可能需要 O(n) 的时间,即线性算法,这在处理大型数据集或进行频繁查询时可能不总是适用的。 HLD 通过将树划分为重路径和轻边来改进这一点。其理念是以一种使查询时间为对数时间而不是线性时间的方式分割树。HLD 分析有助于将树分割成具有特定特征的片段,称为“重”边和“轻”边,这样就可以使用段树或 二进制索引树 (BIT) 等高效数据结构轻松方便地管理和更新跨越树段的操作。 HLD 在任何需要执行诸如处理节点之间路径查询或树分支等操作的问题中都很有用。例如,它可能用于 LCA、路径求和、范围查询或树结构中的动态更改等问题。换句话说,HLD 提供了一种组织树分解的优雅机制,限制了领域范围并提高了性能。 重轻分解的必要性
重边和轻边HLD 的核心概念围绕着将树的边划分为两种类型:重边和轻边。 重边
轻边
重轻分解如何工作?似乎总有几个重要步骤用于在树上执行 HLD,如下所述。因此,当系统地执行这些步骤时,很容易将树分解为各种重路径段,可以使用智能策略轻松管理这些路径的路径查询。过程如下:
如何将树分解为重路径?一旦边被分类,我们就可以开始分解树为重路径的过程。重路径定义为以一个节点开始,仅遍历轻边直到无法形成更重的边。此时,我们停止一条重路径,并且在节点 a 的轻边下的任何子节点将被启动为一条新的重路径。 重路径被假定为尽可能连续。(前景高亮显示);完成此分解后,树被简单地视为一组重路径,轻边被切断在两者之间。通过这种方式分解查询是可能的,因为这种方法可以通过段树或二进制索引树 (BIT) 等技术实现高效的解决方案。 用于查询的段树之后,树被分解,然后利用段树或 BIT 等数据结构在重路径之上进行操作。这允许对重加权路径进行求和、最小值、最大值等探测。查询时会进行过渡以穿过轻边,以便跨越路径并仍然保持 O(log² n) 的高效时间。 重轻分解的应用重轻分解适用于任何涉及树的问题,但对于需要高效处理路径查询和子树查询的问题尤其有用。
编码 您可以在下面的 C++ 中找到 HLD 与段树的实现。该代码对树执行更新和路径查询。 输出 Sum of values between node 7 and 9: 24 Sum of values between node 7 and 9 after update: 32 说明
时间复杂度重轻分解 (HLD) 的时间复杂度取决于两个关键操作:查询和更新。在这里,如果我们按照重路径和轻边划分树,执行这些操作会容易得多。
因此,HLD 处理多个查询和更新时的时间复杂度为每个 O(log² n)。HLD 非常适合解决树上的路径问题,特别是当与段树或任何其他平衡良好的结构相结合时。 结论总之,HLD 算法代表了一种已知的方法,该方法适用于包含路径查询和更新的特定树过程。它将树分割为重边和轻边的列表,以便于将树组织成用于查询的重路径结构。分解过程的第一步包括给树根并使用 DFS 计算子树的大小。这有助于将它们分类为重边(表示对最大子树的贡献)或轻边(其中重边形成反映树的大分支的路径)。 一旦树被分解为这些重路径,每条路径就被视为一个连续的段,这样就可以轻松使用段树或二进制索引树等数据结构来高效地回答路径查询。对于重路径,HLD 直接路由,而对于轻边,它切换到另一条路径,从而将问题分解为几个小问题来解决,并在过程中获得更好的结果。 HLD 的主要优点在于它能够回答路径查询(包括求和查询以及任意两个节点之间的最小或最大查询),并在对数时间内支持动态更新。这使得它在竞赛编程中特别有用,尤其是在频繁进行路径操作的树上。HLD 中查询和更新操作的成本为 O(log² n),因为我们需要遍历多个重路径,然后执行高效的段树操作。 下一主题C++ 中的皮尔逊相关系数 |
简介 C++ 中输入流库的一个重要组成部分是 std::basic_istream::sentry 类,它旨在在执行 I/O 操作之前控制信息流对象的当前条件和能力。Sentry 是一个应用程序类,它确保用户输入操作被执行... ...
阅读 6 分钟
在本文中,我们将讨论 C++ 多线程中的条件变量。但在讨论其条件变量之前,我们必须了解多线程。什么是多线程?多线程是计算机科学和软件开发中的一个基本概念。它涉及在单个……
阅读 4 分钟
C++ 和 C# 都是常见的编程语言,它们都提供独特的特性,用于不同的用例。C++ 是一种面向对象的、中级语言,主要用于系统级编程、游戏开发和关键应用程序。另一方面,C#...
5 分钟阅读
引言 数字自古以来就引起数学家和程序员的兴趣。几种有趣的数列之一是十一边形数,它们因其几何意义而闻名。这些数字代表一个 11 边形或一个 11 边的图形(十一边形),并且可以被描述为三角形的推广……
阅读 4 分钟
C++17 具有多项有价值的特性,可增强语言的表达力和灵活性。“std::variant”是一种强大的处理变体类型的工具。std::variant 存在于 阅读 4 分钟
威尔逊定理指出,根据数学思想的阶乘和模算术的性质,一个数可以被认为是素数。它由数学家约翰·威尔逊(John Wilson)提出,并由约瑟夫·路易斯·拉格朗日(Joseph-Louis Lagrange)证明。它指出:对于正整数 p>1p>1:(p-1)!≡-1(modp)(p-1)!≡-1(modp)。该引理间接说明...
5 分钟阅读
在本文中,我们将讨论 C++ 中的 Moser-de Bruijn 序列及其实现。为了理解这一点,我们回顾了在 C++ 中利用数学关系来识别序列中任何 Nth 项的策略……
阅读 3 分钟
可以被其数字之和整除的数字称为“哈沙德数”或“尼文数”。例如,18 是一个哈沙德数,因为它能被 9 整除,并且 1 + 8 = 9。这个 C++ 程序检查一个整数……
阅读 4 分钟
素数一直吸引着数学家和计算机科学家,因为它们表现出的特殊性质以及在密码学、数论和算法设计中的应用。在许多素数分类中,存在一种有趣但不太为人所知的素数类别,称为……
阅读 4 分钟
在本文中,我们将通过几个例子讨论如何在 C++ 中检查给定数字是否为 Pronic 数。两个连续整数的乘积称为 Pronic 数,有时也称为矩形数。矩形数(也称为 Pronic 数)是...
阅读 4 分钟
我们请求您订阅我们的新闻通讯以获取最新更新。
我们提供所有技术(如 Java 教程、Android、Java 框架)的教程和面试问题
G-13, 2nd Floor, Sec-3, Noida, UP, 201301, India