如何创建具有这种属性的数据结构

时间:2019-02-07 04:56:14

标签: algorithm

我必须设计一个数据结构,以使我拥有一个大小为N的数组A,即A[1],A[1],A[2],...A[n]。我必须处理两种类型的查询(总共有M个查询):

  1. 在数组A中从I到j的范围内加1
  2. 找到数组A中第K个最小的元素

给出1<=N,M<=200000.

首先,我想到通过对每个存储桶进行排序来进行平方根分解,但是无法更新属于不同存储桶的部分范围。你能建议怎么做吗?

我想要一些O(N*Log(N))O(N*SQRT(N))的复杂性。

1 个答案:

答案 0 :(得分:0)

这看起来是一个非常典型的竞争性编程问题。我觉得我有一个解决方案,尽管它有点难看-也许您可以改进它。

我们将在解决方案的核心中使用平方根分解(如果您不熟悉此方法,请参见link)。对于每个块,我们将保留:元素的值保持不变(将其命名为A),整个块的加法数(一个整数,将其命名为extra)和{{1} }-按值对块索引进行排序(例如,如果块元素为[4、2、5],则索引数组为[1、0、2])。现在,让我们看一下这如何使我们解决问题以及复杂性如何。

初始化

对于每个IND块,我们都必须对其进行排序(每个块sqrt(N)),以获得初始索引数组,从而导致sqrt(N) * log(sqrt(N))的初始化复杂度。

在范围(l,r)中加1

继续进行常规的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)

找到第K个最小元素

让我们弄清楚如何找到数组中小于某个值M * sqrt(N) * log(N)的元素数。为此,对于每个块,我们将对L数组进行二进制搜索。当我们从该数组获得某个索引IND时,要使用的实际值为idx,其中A[idx] + extraA来自该块。此过程使我们能够在每个块中获取大于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之一可以被剃掉,但这留给读者作为练习:)