是的,这可以在 O(log n) 中完成,即使您应该在线回答查询。然而,这需要一些相当复杂的技术。
首先,让我们解决以下问题:给定一个数组,回答“索引 [l, r] 中有多少个 <= x 的数字”形式的查询。这是通过有时称为合并排序树的分段树状结构完成的。它基本上是一个分段树,其中每个节点都存储一个排序的子数组。这种结构需要 O(n log n) 内存(因为有 log n 层,每个层都需要存储 n 个数字)。它也内置在 O(n log n) 中:您只需自下而上,并为每个内部顶点合并其子级的排序列表。
这是一个例子。说1 5 2 6 8 4 7 1
是一个原始数组。
|1 1 2 4 5 6 7 8|
|1 2 5 6|1 4 7 8|
|1 5|2 6|4 8|1 7|
|1|5|2|6|8|4|7|1|
现在您可以在 O(log^2 n 次) 内回答这些查询:只需对分段树进行定期查询(遍历 O(log n) 个节点)并进行二进制搜索以了解有多少数字 <= x在那个节点中(额外的 O(log n) 从这里)。
使用分数级联技术可以将其加速到 O(log n) ,这基本上允许您不在每个节点中而是仅在根中进行二进制搜索。然而,它足够复杂,可以在帖子中描述。
现在我们回到原来的问题。假设您有一个数组 a_1, ..., a_n。构建另一个数组 b_1, ..., b_n,其中 b_i = 数组中下一次出现 a_i 的索引,如果是最后一次出现,则为 ∞。
示例(1 索引):
a = 1 3 1 2 2 1 4 1
b = 3 ∞ 6 5 ∞ 8 ∞ ∞
现在让我们计算 [l, r] 中的数字。对于每个唯一编号,我们将计算其在该段中的最后一次出现。使用 b_i 概念,您可以看到数字的出现是最后一个当且仅当b_i > r
。因此,问题归结为“[l,r] 段中有多少个数字 > r”,这被简单地简化为我上面描述的内容。
希望能帮助到你。