Description
给定 $n$ 个数 $a_i$,$m$ 个询问,求区间 $[l,r]$ 中的最小众数,强制在线。
$(1 \leq n \leq 10^4,1 \leq m \leq 2 \times 10^4, 1 \leq a_i \leq 10^9)$
Source
Solution 1
考虑 分块 。我们可以预处理出 $f_{i,j}$ 为第 $i$ 个块到第 $j$ 个块的区间最小众数,那样区间 $[l,r]$ 的答案只有可能是 中间所有块的区间最小众数,左边多余块中的数 或 右边多余块中的数(如图)。
很容易在 $O(块的大小 \times n)$ 的时间内预处理出所有的 $f_{i,j}$,但是怎么求出左右多余块中的数在区间 $[l,r]$ 中的出现次数呢?我们可以用 $\rm vector$ 存下每一个 $a_i$ 在序列中的所有出现位置(要先离散化)。在询问时,对于左右多余块中的每一个数 $x$,我们可以二分找到端点 $l,r$ 在 $x$ 对应的 $\rm vector$ 中的位置(可以用 $\rm STL$ 中的 $\rm lower\_bound$ 和 $\rm upper\_bound$),相减即是 $x$ 在区间 $[l,r]$ 中的出现次数。注意如果该数的出现次数与当前答案的出现次数相同,但这个数更小,也要更新答案,因为要求的是最小众数。
设块的大小为 $S$,则总时间复杂度为 预处理 $O \left( \frac{n^2}{S} \right)$ + 查询 $O(mS\log n)$,根据 均值不等式,可知取 $S = \frac{n}{\sqrt{m \log n}}$ 时总时间复杂度最小,为 $O(n \sqrt{m \log n })$ 。
Code 1
1 |
|
Solution 2
考虑怎么优化上述做法(即减少查询的时间复杂度)。
很容易发现查询时答案在区间 $[l,r]$ 中的出现次数其实是单调不减的。
我们可以预处理出 $pos_i$,表示 $i$ 的位置在 $a_i$ 的 $\rm vector$ 中对应第几个数。假设当前我们已经知道当前的最小众数是 $mode$,且 $mode$ 的出现次数为 $maxn$ 。左边和右边多余的块分类讨论:
对于左边多余块中的某个数 $x$,$x$ 在其对应 $\rm vector$ 中的位置是 $pos_x$ 。我们只需要判断 $x$ 出现的次数是否大于或等于 $maxn$ 即可,因为如果这个数出现的次数小于 $maxn$,就不可能更新答案。如果 $x$ 第 $pos_x + maxn$ 次出现的位置 $\leq r$,就说明区间 $[l,r]$ 中 $x$ 的出现次数为 $maxn + 1$,比当前答案更优。如果 $x$ 第 $pos_x + maxn - 1$ 次出现的位置 $\leq r$,且 $x$ 比答案小,就说明 $x$ 也能更新答案。
右边多余的块同理,只是变成了判断 $x$ 第 $pos_x - maxn$ 次出现的位置是否 $\geq l$ 。
写代码时有很多细节需要注意。比如要先判断 $\rm vector$ 的下标是否小于 $0$ 或者超过 $size$,然后再访问。
很显然这种做法在查询时不需要二分,时间复杂度少一只 $\log$ 。设块的大小为 $S$,则总时间复杂度为 预处理 $O \left( \frac{n^2}{S} \right)$ + 查询 $O(mS)$,根据 均值不等式,可知取 $S = \frac{n}{\sqrt m}$ 时总时间复杂度最小,为 $O(n \sqrt m)$ 。
Code 2
1 |
|