给出长度为 n (<= 500000)的数组 A 。
A [ i ] <= 10 ^ 9。
有两种类型的 q (<= 50000)条查询:
用于查询的原始O( n )和用于更新的O(1)太慢-通常为O( n ^ 2)。
您能否提出有效的算法/数据结构来解决此问题?
答案 0 :(得分:1)
您可以使用段树,数据结构和复杂度将为O(nlogn + qlogn)
。如果您不熟悉Segment tree,则最好收集有关它的知识。您会在网上找到很多有关它的资源。
在段树中,通常每个节点都保留有关特定范围的信息。通常,叶节点保留有关特定数组索引的信息,内部节点从其左,右子节点生成或更新信息。
请考虑以下情况,以找出A
范围内[l, r]
中未出现的最小正整数:
对于答案为1的情况:
如果该范围内的最小值大于1,则答案为1。为此,构建一个段以查找该特定范围内的最小值。参见下图:
从上图可以看出,叶节点保存了特定的数组索引值,内部节点从其左右子值(min(left child's min value, right child's min value)
)更新其值。从该细分中,我们可以找到O(logn)
中任何范围的最小值。如果任何数组索引值发生变化,我们可以在O(logn)
中更新树。
对于答案为(范围的最大值)+1的情况:
为此,构建一个细分以查找在此特定范围内的最大值。它类似于上面的段树,我们不会找到最小值,而是找到最大值。
对于答案既不是1也不是(范围的最大值)+1的情况:
在这种情况下,我们将需要一个细分树,该树将给出最小的缺失正值,该缺失值大于范围[l,r]
的最小值且小于范围[l,r]
的最大值。
我们将使用值0
表示此范围[l,r]
中没有缺失值。
对于叶节点,我们将缺失值设置为0
。
现在我们将如何计算内部节点的缺失值。
假设对于内部节点P
,我们将计算缺失值。 P
的左孩子L
和右孩子R
。
P
的缺失值将使用以下过程进行计算:
P.Missing_Value = infinite value
// for the case L = {1,2} , R = {4,5}
if L.Max_Value+1 < R.Min_Value {
P.Missing_Value = min(P.Missing_Value, L.Max_Value + 1)
}
// for the case L = {4,5} , R = {1,2}
if R.Max_Value+1 < L.Min_Value {
P.Missing_Value = min(P.Missing_Value, R.Max_Value + 1)
}
// for the case L = {1,3} , R = {1,3,4,5} or L = {1,3} , R = {4,5} or L = {3,5} , R = {1,2}
if L.Missing_Value != 0 && (L.Missing_Value < R.Min_Value || L.Missing_Value > R.Max_Value || L.Missing_Value == R.Missing_Value) {
P.Missing_Value = min(P.Missing_Value, L.Missing_Value)
}
// for the case R = {1,3} , L = {1,3,4,5} or R = {1,3} , L = {4,5} or R = {3,5} , L = {1,2}
if R.Missing_Value != 0 && (R.Missing_Value < L.Min_Value || R.Missing_Value > L.Max_Value || R.Missing_Value == L.Missing_Value) {
P.Missing_Value = min(P.Missing_Value, R.Missing_Value)
}
// if there is no missing value
if P.Missing_Value == infinite {
P.Missing_Value = 0
}
完成
上述树将成为您的最终细分树。从中可以查询任何范围的最小值,最大值和缺失值。这些查询和更新(如果数组索引值更改)将花费O(logn)
。
有关分段树的一些教程/资源: