我已经通读了一些有关两个常见数据结构的教程,可以在O(lg N)中实现范围更新和查询:段树和二进制索引树(BIT / Fenwick树)。
我发现的大多数示例都是关于一些关联和交换运算的,例如“范围内的整数之和”,“范围内的XOR整数”等。
我想知道这两个数据结构(或其他任何数据结构/算法,请提出)是否可以在O(lg N)中实现以下查询?(如果否,那么O(sqrt N)怎么样?)
给定整数A的数组,查询范围[l,r]中不同整数的数量
PS:假设可用整数的数量为〜10 ^ 5,所以 used[color] = true不能使用位掩码
used[color] = true
例如:A = [1,2,3,2,4,3,1],query([2,5])= 3,其中范围索引从0开始。
是的,即使您应该在线回答查询,也可以在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 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”,这被微不足道地简化为我上面所描述的。
希望能帮助到你。