所以我试图解决这个编程问题。
给出一组数字和一些查询。每个查询都会给出三个数字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)),但速度不够快。我在寻找更好的算法。我认为查询的平方根分解是行不通的。有没有更好的算法来解决这个问题?
我想知道某些数据结构是否可以解决我不知道的问题?
答案 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)
根据 c 对查询进行排序
按非降序排列数组值
维护(位|段树)用于存储范围总和
在回答当前查询之前,更新所有数组的索引 其值 <= c
的元素回答范围查询求和问题。
时间复杂度:(n+q)*log(n)
,空间复杂度:O(n)