乘以一系列数字而忽略重复

时间:2015-10-11 02:59:00

标签: algorithm data-structures

给定一个数组和一些q范围查询。

在单个查询中,我想在一系列索引中打印产品,而忽略重复项,索引从1开始。

例如,如果数字是:

8 1 3 2 4 1 3 3 1

对于索引1到8的范围查询:产品将是1 * 2 * 3 * 4 .i.e 24。 对于索引6到7的范围查询:产品将为3。

是否可以使用分段树或任何预处理来回答log(n)中的范围查询,或者使用xor或任何其他方法有任何技巧。

1 个答案:

答案 0 :(得分:1)

是的,每次查询都可以获得O(log N),但解释会有点长......

此问题可以描述为"唯一范围的产品查询"。这类似于"唯一范围和查询"问题,你想要的是和,而不是产品或独特的元素。

唯一范围求和查询类似于"范围内不同元素的数量"问题,一个described here的解决方案。这篇文章不容易理解(特别是如果你还没有在很高的水平上完成很多算法编程竞赛),所以我将解释"范围内不同元素的计数" ;在这里更详细。

计算范围

中的不同元素
  

假设您有values = [1, 2, 3, 1, 2, 1, 3]。对于每个值,你   想要找到具有相同值的下一个位置。这是   nextposes = [4, 5, 7, 6, inf, inf, inf]。假设你有   query = [2, 6]nextposes = [5, 6, 7, inf, inf],其中3个> 6,所以   答案是3。

这是我从帖子中复制示例的简单部分。这给出了我们想要解决的问题的想法,但不是以易于理解的方式。下一个想法是将它放在2D树中。这篇文章并没有解释这是如何运作的,所以我在这里解释一下。

2D树是分段树的分段树。因此,您需要构建一个分段树,并在第一个分段树的每个顶点中构建另一个分段树。您还必须确定要在段树中放置的内容。从上面的示例中,2D segtree描述了2D平面。平面中有许多点,并且您希望将它们插入到结构中。示例中的点是(1, 4), (2, 5), (3, 7), (4, 6), (5, inf), (6, inf), (7, inf)。那是(x,y) = (array position, next array position)。如果在平面上绘制这些图形,您将意识到对于每个查询,您必须计算矩形区域中的点数。在给出的示例中,您想要计算2 <= x <= 6, y > 6的点数。如果您遍历细分树,则执行此操作需要O(log^2 N)。要更新树,还要遍历段树,并且成本相同。

优化

如果你做了一个天真的2D段树,它会花费你O(N*max(V))内存(其中max(V)是最大可能的整数值),并且可能与获取此内存的时间相同。事实上,你不需要那么多记忆。您可以构建一个延迟初始化的2D段树。这意味着您从树顶部的单个节点开始表示整个范围,并且只在需要时将其拆分(因为您在树中插入了某些内容)。这会将内存成本降低到O(N log^2 (N))

唯一范围和查询

要获得总和,可以对插入到2D树中的每个顶点进行加权。不要认为你需要在帖子中提到的treap。

唯一范围产品查询

而不是添加,每次要添加时,只需相乘。

最后,算法复杂度为O((N + Q) log^2 N)。在每次查询O(log^2 N)时,这不如您要求的每个查询log(N)那么好。我现在将解释如何在每个查询中获得O(log N)

每个查询

O(log N)

为实现这一目标,我们可以使用持久性数据结构。持久性数据结构是一个可以修改它的数据结构(即进行更新),您将获得一个带有更新的新结构,并且您还可以在更新之前保留旧结构(有点像不可变字符串)。但是,持久性结构以优化的方式执行此操作,因为旧的和新的数据结构将共享其大部分内容。对于分段树,假设您要对位置进行更新。您只需要在到新位置的路径上创建新节点(即需要重新创建O(log N)节点)。其余节点可以与旧数据结构中的节点相同。

现在我们知道持久数据结构是什么,我们的想法是先把我们插入到2D树中的(x,y)坐标。这次,我们想要按y坐标降序对它们进行排序。然后我们按顺序将这些点插入到一维持久性分段树中。每次插入的费用为O(log N)

每次插入后,我们会保留一个指向段树根节点的指针数组。因此,对于y > some number的每个约束,我们有1个分段树。

现在像以前一样查询矩形区域2 <= x <= 6, y > 6,我们首先找到代表y > 6的分段树(就在我们插入点(4,6)之前)。然后,我们会对范围[2,6]进行范围 - 产品查询,费用为O(log N)次。

由于构建N持久段树成本O(N log N),并且每个查询都是O(log N),因此总时间复杂度为O((N + Q) log N)

此解决方案的实现非常复杂,因为您需要创建一个持久的,延迟初始化的分段树。但是,我确实认为编写一维持久分段树比二维分段树更容易。