📜  重光分解|设置1(简介)

📅  最后修改于: 2021-04-17 13:43:20             🧑  作者: Mango

重轻分解(HLD)是竞争性编程中最常用的技术之一。

示例问题:让我们借助以下示例理解重轻分解(HLD)。

假设我们有一个n个节点的不平衡树(不一定是二叉树) ,并且我们必须对该树执行操作以回答许多查询,每个查询可以是以下两种类型之一:

  1. 变化(A,B):a边缘至b的更新权重。
  2. maxEdge(a,b) :在从节点a到节点b的路径上打印最大边缘权重。例如maxEdge(5,10)应该打印25。

假定节点从1到n编号。必须有n-1条边。边缘权重是自然数。还假设两种查询都是散布的(数量大约相等),因此没有一种类型的查询可以在边际上妥协以降低复杂性。

hld1

简单的解决方案:一个简单的解决方案是遍历任何查询的完整树。此解决方案中每个查询的时间复杂度为O(n)。

基于HLD的解决方案:

通过仔细观察这两个操作,我们意识到我们已经在某个地方看到了它们。尤里卡!段树。段树可用于执行O(log(n))中的两种类型。可是等等!可以从一维数组/链(一组节点相互链接)中构建一个“分段树”,这里就是一棵树。那么,我们可以将树简化为链条吗?

帖子中讨论的基于HLD的解决方案对maxEdge()而言为O(log 2 (n)),对于change()而言为O(log n)。

节点x的大小是以该节点x为根的子树中的节点数。这是一张显示每个节点的子树大小的图像,这些子树写在它们的顶部:
hld2

根树的HLD是一种将树的顶点分解为不相交的链(没有两个链共享一个节点)的方法,以针对涉及树木的某些问题获得重要的渐近时限。

HLD也可以看作是树边缘的“着色”。 “重光”来自我们分离边缘的方式。我们使用以节点为根的子树的大小作为我们的标准。

如果size(v)> size(u),则边缘很重,其中u是v的任何同级。如果它们相等,则选择v中的任意一个作为特殊对象。

hld3

change(u,v)操作:
由于段树用作表示单个链的基础数据结构,因此更改是使用段树的更新完成的。因此,更改操作的时间复杂度为O(Log n)。

maxEdge(u,v)操作:

    1. 我们首先找到两个节点的LCA。假设节点u为11,节点v为9。它们的LCA为节点1。
    2. 然后,我们将树从节点u爬到lca。如果节点u和lca属于同一链,则使用段树从代表它们之间边缘的范围中找到最大值。否则,我们从u所属的链中找到最大值,然后更改链并在我们不在同一链中时重复。
    3. 我们从v到lca重复相同的步骤(作为步骤2),并返回两个权重的最大值。

根据上面的示例,让我们将u当作节点11,将v当作节点9。LCA是节点1。我们从节点11移到节点1,并且改变链一次。更改链时,我们从查询的节点转移到它所属链的头的父节点(此处11变为8)。类似地,查询节点9到节点3(包括亮边),并更改链(节点更改为1)。

重轻分解

hld8

maxEdge的时间复杂度为O(log 2 (n))。查询一条链的最大值需要O(log(n))时间,因为使用段树表示链,并且最多有O(log(n))条链。

链数O(log(n))如何?
所有链条均通过轻边缘连接(请参见上面的示例)。因此,链条的数量以任何路径上的光边缘的数量为界。如果我们从根开始跟随浅边缘,则以结果顶点为根的子树的大小最多为n / 2。如果重复,我们将以子树大小最大为n / 4的顶点着陆,依此类推。我们得出结论,从根到叶的任何路径上的光边缘数量最多为log(n) (来源: wcipeg )

不平衡树的重轻分解的主要思想是将长(或重)路径的顶点串在一起成链,这样就可以使用段树之类的数据结构在O(Log n)时间查询这些线性链。

在下一篇文章中,将更详细地讨论链的段树表示形式以及该问题的HLD解决方案的实现。

重光分解|套装2(实施)