一尘不染

范围最小查询 方法(从树到受限RMQ)

algorithm

所以,我读
TopCoder的教程RMQ(范围最小查询),和我有一个很大的问题。

在他介绍该方法的部分中,到目前为止,我仍然可以理解:

(整个方法实际上使用的是稀疏表(ST)算法中引入的方法,即从LCA还原为RMQ以及从RMQ
还原为LCA

给定数组A
[N],我们需要将其转换为笛卡尔树,从而使RMQ问题成为LCA(最低公共祖先)问题。稍后,我们可以获得阵列A的简化版本,并将其作为受限的RMQ问题。

因此,基本上是两个转换。因此,第一个RMQ至LCA部分很简单。通过使用堆栈,我们可以在O(n)时间内进行转换,从而得到一个数组T [N],其中T
[i]是元素i的父元素。树完成了。

但是,这是我无法理解的。O(n)方法需要一个数组,其中|A[i] - A[i-1]| = 1,该数组在本教程的“
从LCA缩减为RMQ”部分中介绍。这涉及到这棵树的欧拉之旅。但是如何用转换的最终结果来实现呢?我的方法不是线性的,因此在这种方法中应该认为它是不好的,对此,线性方法是什么?

更新:这一点让我感到困惑

Here's the array A[]:

  n : 0  1  2  3  4  5  6  7  8  9
A[n]: 2  4  3  1  6  7  8  9  1  7

Here's the array T[]:

  n : 0  1  2  3  4  5  6  7  8  9
T[n]: 3  2  0  *  8  4  5  6  3  8  // * denotes -1, which is the root of the tree

//Above is from RMQ to LCA, it's from LCA to RMQ part that confuses me, more below.

树的图片:

数据中的笛卡尔树

像DFS(深度优先搜索)一样,Euler Tour需要知道每个节点的子节点,而T [n]仅具有每个元素的根,而不是子节点。


阅读 261

收藏
2020-07-28

共1个答案

一尘不染

这是我目前对让您感到困惑的事情的理解:

  1. 为了将RMQ减少为LCA,您需要将阵列转换为树,然后对该树进行Euler游览。
  2. 为了进行Euler游览,您需要存储树,使得每个节点都指向其子节点。
  3. 从RMQ到LCA列出的缩减每个节点都指向其父节点,而不是其子节点。

如果是这种情况,您的顾虑是完全合理的,但是有一种简单的方法可以解决此问题。具体来说,一旦有了所有父指针的数组,就可以将其转换为树,其中每个节点在O(n)时间内指向其子节点。这个想法如下:

  • 创建一个n个节点的数组。每个节点都有一个值字段,一个左子节点和一个右子节点。
  • 最初,将第n个节点设置为具有左子级无效,右子级无效以及数组中第n个元素的值。
  • 遍历T数组(其中T [n]是n的父索引)并执行以下操作:
    • 如果T [n] = *,则第n个条目是根。您可以将其存储以备后用。
    • 否则,如果T [n] <n,则您知道节点n必须是其父节点的右子节点,该父节点存储在位置T [n]。因此,将第T [n]个节点的右子节点设置为第n个节点。
    • 否则,如果T [n]> n,则您知道节点n必须是其父节点的左子节点,该子节点存储在位置T [n]中。因此,将第T [n]个节点的左子节点设置为第n个节点。

由于每个节点仅被处理一次,因此运行时间为O(n)。

完成此操作后,您已经明确构建了所需的树结构,并具有指向根的指针。从那里开始,继续进行算法的其余部分应该相当简单。

希望这可以帮助!

2020-07-28