我必须设计一个数据结构,以使我拥有一个大小为N的数组A,即A[1],A[1],A[2],...A[n]
。我必须处理两种类型的查询(总共有M个查询):
给出1<=N,M<=200000.
首先,我想到通过对每个存储桶进行排序来进行平方根分解,但是无法更新属于不同存储桶的部分范围。你能建议怎么做吗?
我想要一些O(N*Log(N))
或O(N*SQRT(N))
的复杂性。
答案 0 :(得分:0)
这看起来是一个非常典型的竞争性编程问题。我觉得我有一个解决方案,尽管它有点难看-也许您可以改进它。
我们将在解决方案的核心中使用平方根分解(如果您不熟悉此方法,请参见link)。对于每个块,我们将保留:元素的值保持不变(将其命名为A
),整个块的加法数(一个整数,将其命名为extra
)和{{1} }-按值对块索引进行排序(例如,如果块元素为[4、2、5],则索引数组为[1、0、2])。现在,让我们看一下这如何使我们解决问题以及复杂性如何。
对于每个IND
块,我们都必须对其进行排序(每个块sqrt(N)
),以获得初始索引数组,从而导致sqrt(N) * log(sqrt(N))
的初始化复杂度。
继续进行常规的sqrt分解更新。对于完全在范围内的每个块,我们将增加sqrt(N) * sqrt(N) * log(sqrt(N)) = N * log(N)
计数器。至关重要的观察是元素的相对顺序不会改变,因此我们在这里的工作已经完成。对于部分在更新范围内的块,我们执行以下操作:通过将适当的元素增加1来更新extra
,并通过排序来重新生成A
数组。注意,最多有两个部分更新块。 IND
中“完整”块更新的总复杂度,其中有O(1)
个。部分更新为sqrt(N)
,因此更新总复杂度为sqrt(N) * log(sqrt(N)) = sqrt(N) * log(N)
。有M个查询,因此最糟糕的是这些更新将贡献sqrt(N) * log(N)
。
让我们弄清楚如何找到数组中小于某个值M * sqrt(N) * log(N)
的元素数。为此,对于每个块,我们将对L
数组进行二进制搜索。当我们从该数组获得某个索引IND
时,要使用的实际值为idx
,其中A[idx] + extra
和A
来自该块。此过程使我们能够在每个块中获取大于extra
的元素数量。然后,我们只对每个块的结果求和。要处理一个块,我们必须在二进制搜索上花费L
,并且有log(sqrt(N)) = log(N)
个块,从而导致sqrt(N)
的复杂性。
要获得第K个最小元素,我们将对可能的答案(竞争编程中的通用技术)进行另一次二进制搜索,我们将在最小和最大可能答案之间进行二进制搜索(例如,最小元素和最大元素加sqrt(N) * log(N)
)。让我们将此范围表示为M
。在每一步中,我们检查比当前的猜测少多少个元素,当我们找到第K个最小的元素时,我们将得到答案。让我知道您是否需要详细说明这一步骤。
最终复杂度为C
,并且可以有M个查询,使其成为log(C) * sqrt(N) * log(N)
。如果初始数组全为零或值在M * log(C) * sqrt(N) * log(N)
至0
范围内,则该值为M
。或者,您可以选择将M * log(M) * sqrt(N) * log(N)
视为常量(不太正确)。
我很确定C
之一可以被剃掉,但这留给读者作为练习:)