【问题标题】:Range Update and Query on array数组的范围更新和查询
【发布时间】:2018-11-10 10:03:06
【问题描述】:

我对具有 n 个元素的数组 A 有更新和查询。
我有两种查询:
类型 1(更新):给定 x,递减数组 A 中值大于或等于 x 的所有元素的值。
type 2 (Query) : 给定 (l, r, x),找出数组 A 中第 x 个最小的元素,其值介于 l 和 r(均包含)之间。

我想不出比蛮力更好的解决方案,它可能与 O(q*n) 一样昂贵。有没有最佳解决方案? 数组 A 的元素最大可达 10^18。

【问题讨论】:

    标签: algorithm data-structures


    【解决方案1】:

    我正在考虑的数据结构是自平衡二叉树的增强变体,例如 AA 树。除了普通成员之外,每个节点还存储了一个递减计数,这些递减计数隐式应用于其后代。与其更改数字本身,不如从每个祖先节点中减去递减计数来查看节点的最终值。每个节点还维护其后代的计数。

    更新包括对树的绑定搜索(复杂度O(log n)),并增加O(log n) 节点的递减计数。在某些情况下,您还必须将边界下方的元素移动到该树中(因为它们不再小于所有元素,这要归功于递减),这也是O(log n)。 (请注意,最后一点需要进行一些棘手的后代更新,但我认为这不会超出总体界限。)

    “查询”操作很简单;二进制搜索找到lr 与操作无关,AFAICT)然后使用后代计数加速找到该范围内的第 k 个最小到 O(log k)

    所以这两个操作都有时间O(log n),总时间是O(q*log n),假设你不计算O(n*log n)时间来构建初始树。

    【讨论】:

      【解决方案2】:

      没有比O(n) 更快地运行每个描述的查询更好的解决方案,其中 n 是数组元素的数量,在您描述问题时始终在未排序的数组上。那是因为您必须为查询考虑数组中的每个元素。问题是您没有关于您的数据的信息,因此您永远不知道在哪里检查以使事情变得更快。

      如果您要进行大量查询,您可以通过对数组进行排序并保持排序来进行一些优化。虽然排序最初将采用O(n log(n))(快速排序、合并排序),但它允许您使用修改后的二分搜索(查找范围内的第一个最小元素,然后取下 x 个元素)。 (如果你使用像 qsort 这样的库排序,你会以 1.3 nlog(n) 之类的方式排序,这非常好)

      它还可以让您更快地执行更新,因为您可以再次使用 BSearch 来获取您正在寻找的值。在这里,有关数据的知识很重要。如果你的减量不会改变顺序很多(检查边界案例元素),那么从长远来看这更有效。

      如果您的数组已排序,您还可以通过仅考虑第一个元素左侧的元素大于或等于 x 来有效地在 Q1 之后进行排序。如果这些元素中的一些现在比您的一些减少的元素大,您可以找到它们之间的边界并在第一季度之后在较小和较大区域之间进行交换(智能排序,使用您在数据上的信息)。

      如果您不能对数据进行排序(出于绘图目的等),那么线性时间是您所希望的最佳选择。如果您的数组很小,也不需要排序,这将是矫枉过正,不会带来明显的改进。老实说,线性时间在现代计算机上真的很好用。

      【讨论】:

      • 你说查询,我应该使用排序,但我可以使用快速选择算法在 O(n) 中找到未排序数组中的第 x 个元素。但主要问题是时间复杂度是O(q*n),加上q和n最多2*1​​0^5!!
      • @Raghav James 正如我所说,排序只是为了让您在长期中创造更好的性能。您在 O(n) 中查找元素是正确的,但是对于您的查询,您还必须找到该范围内的所有元素,问题是您的限制是您需要 x 最小的元素。因此,如果您在范围内有 k > x 元素,则需要弄清楚要取哪个 k。无论如何,如果您的数组大小为 2*10^5,那么在开始时排序一次,然后保持排序长期中可能会更快。您没有在每次查询后进行完整排序!
      • 好的,所以我最初对数组进行了排序。但是,我该怎么做更新操作。即使在更新数组后,如何通过将数组值递减 x 来使数组保持排序状态。每次更新后我是否应该再次对数组进行排序?
      • 如果需要排序,您只需在更新后“冒泡”更改的结果,因此这也将是 O(log(n))(O(n) 与上面最差的相同)。假设您在范围内的第一个元素称为b,左边的一个(下一个最小的)a。现在如果b在减量后小于a,则找到b之后的下一个元素(命名为c,使用二分查找),它大于a。现在您将a 移动到c 之前,然后重复(总是找到新的c)直到b >= a。在最坏的情况下,这将是 O(m*log(m)),其中 m 是更新子数组的大小。
      猜你喜欢
      • 1970-01-01
      • 2023-02-22
      • 1970-01-01
      • 2016-03-02
      • 1970-01-01
      • 1970-01-01
      • 2021-08-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多