子阵列查询

时间:2017-06-06 17:31:24

标签: algorithm optimization data-structures tree

所以我试图解决这个编程问题。

给出一组数字和一些查询。每个查询都会给出三个数字a,b,c,并要求您回答索引a到索引b(包括两者)中小于或等于c的所有元素的总和。

例如:

给定数组:{2,4,6,1,5,1,6,4,5,4}

要回答3个问题:

2 4 4 - > ans = 5即{4 + 1}

1 5 3 - > ans = 3即{2 + 1}

4 5 1 - > ANS = 1

数组中的每个值小于10 ^ 5,数组的长度和查询的数量可以达到10 ^ 5

这就是我所做的我用Mo的算法(平方根分解)对查询进行排序,并创建了一个二进制索引树来存储元素的累积和小于1-10 ^ 5的所有值,并且做了一个更新从查询到查询的更新。使用这种算法,我的解决方案的整体复杂性是O(q * sqrt(N)* log(N)),但速度不够快。我在寻找更好的算法。我认为查询的平方根分解是行不通的。有没有更好的算法来解决这个问题?

我想知道某些数据结构是否可以解决我不知道的问题?

2 个答案:

答案 0 :(得分:2)

你可以反过来分解它。即,构建一个半数组树(这是( n log n )空间)。对每个子阵列进行排序并为其构建累积和数组。现在您的查询(log 2 n )每个(log n 用于标识子数组,另一个日志 n 到找到每个子阵列的累积和)。

例如,如果您的原始数组是

            5,10,2,7,16,4,8,9

首先构建此树

            5,10,2,7,16,4,8,9
              /         \
      5,10,2,7           16,4,8,9
      /      \           /      \
    5,10     2,7      16,4      8,9
    / \      / \      / \       / \
   5   10   2   7   16   4     8   9

然后将它们全部排序

           2,4,5,7,8,9,10,16
              /         \
      2,5,7,10           4,8,9,16
      /      \           /      \
    5,10     2,7      4,16      8,9
    / \      / \      / \       / \
   5   10   2   7   16   4     8   9

现在,如果你想回答查询说(1,6,8)(索引是从0开始),你将(1,6)区间分解为二进制子区间(1)(2,3)(4,5) (6)(那里不超过2 log n )然后分别找到每个的答案(0表示(1)= {10},9表示(2,3) )= {2,7},4表示(4,5)= {16,4},8表示(6)= {8})并总结它们。

初始树构建可以在( n log n )中完成,如果您对对(值,索引)进行排序一次,然后只是将已排序的数组日志传递n次(每个树级别一次)并将值复制到各自的节点。

答案 1 :(得分:0)

  1. 根据 c 对查询进行排序

  2. 按非降序排列数组值

  3. 维护(位|段树)用于存储范围总和

  4. 在回答当前查询之前,更新所有数组的索引 其值 <= c

    的元素
  5. 回答范围查询求和问题。

时间复杂度:(n+q)*log(n),空间复杂度:O(n)