我们正式给出了一个带有一些初始值的数组。然后我们有3种类型的查询: -
N = 10 5 ,Q = 10 5 (数组中的元素数,查询数)。
我尝试使用分段树执行此操作,但操作2,3可能比O(n)更差,即使我们不知道哪个范围'要完全更新,以便最终遍历整个分段树。
注意:我希望清楚,如果我们需要在对数最差情况下进行所有3个操作,即O(log n),那么只有这样我们才能做到这一点,快速,线性方法不会&# 39; t作为Q = 10 ^ 5 n N = 10 ^ 5,因此最坏情况可能是O(n ^ 2),即10 ^ 10运算,这显然是不可行的。
答案 0 :(得分:1)
鉴于您正在讨论10个 5 项目,并且没有提及需要添加或删除项目,在我看来,明显的数据结构将是一个简单的排序向量。 / p>
操作复杂性:
m
是后续元素的数量,等于更新前的值。)n
是范围的开头,m
是范围内的元素)。要确定“快速”对你意味着什么有点困难,但理论上最快的1是O(1),所以我们已经处于最佳的常数因素之内。
对于2和3,即使我们能够以恒定的复杂度进行查找,我们也几乎坚持使用O(m)进行更新。由于Log 2 100000 = ~16.6,大多数时候O(m)项将占主导地位(即,更新部分将涉及与搜索一样多的操作,除非给定{{1} }是该集合中最后17个项目之一。
我怀疑这个小集合有什么意义,但如果你可能不得不处理一个更大的集合,并且集合中的项目可以合理地预测分布,那么可能值得考虑进行插值搜索而不是二分搜索。通过可预测的分布,这将预期的比较次数减少到大约O(log log n)。在这种情况下,这大约是4(但通常具有更高的常数因子)。这个可能是10个 5 项目的胜利,但是它可能不会。如果您可能需要处理(例如)10个 8 项目或更多项目的集合,那么它将更有可能获得实质性的胜利。
答案 1 :(得分:0)
以下可能不是最佳选择,但是今晚我能想到的最好。
让我们首先尝试将问题转向侧面。我们不是考虑从索引到值的映射,而是考虑从值到索引集的映射。点更新现在涉及从一个集合中删除索引并将其添加到另一个集合。范围更新涉及将索引集从一个值移动到另一个值或者将两个索引集合并在一起。范围查询涉及折叠对应于范围中的值的集合。快速浏览维基百科表明,传统的disjoint-set data structure对于集合联盟来说真的很棒。不幸的是,从集合中删除元素并不是一件好事。
幸运的是,有一个更新的数据结构支持union-find with constant time deletion!这很自然地处理了点更新和范围更新。遗憾的是,范围查询将需要检查所有数组元素,即使很少有元素在范围内。