题解:P13984 数列分块入门 9
Chenyichen0420 · · 题解
思路分析
当时学的时候觉得最难的一道题,甚至觉得没法做,不过事实上狭隘了。
首先,我们很套路的将整个序列按照
不难想到我们可以选择先维护出
直观上讲,一个区间内的众数确实可能会有很多个,我们只取其中的最小的那个是不是有问题呢?这个数不一定是原序列上完整区间的众数!
我们继续思考,假设我们要求的原区间是
因此,可能成为答案的数只可能是中间那一大段的众数,或者边角料上出现的数。出现次数我们可以选择用 vector 维护每个数出现的位置,然后用二分求解。
总时间复杂度
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define sipt
#define sopt
struct IO {
#define mxsz (1 << 21)
char buf[mxsz], * p1, * p2;
char pbuf[mxsz], * pp;
IO() : p1(buf), p2(buf), pp(pbuf) {}
~IO() { fwrite(pbuf, 1, pp - pbuf, stdout); }
inline char gc() {
if (p1 == p2) p2 = (p1 = buf) + fread(buf, 1, mxsz, stdin);
return p1 == p2 ? ' ' : *p1++;
}
#ifndef sipt
inline int read() {
int r = 0; char c = gc(); while (c < '0' || c>'9') c = gc();
while (c >= '0' && c <= '9') r = r * 10 + (c ^ 48), c = gc();
return r;
}
#else
inline int read() {
int r = 0; char c = gc(); bool rev = 0;
while (c < '0' || c>'9') rev |= (c == '-'), c = gc();
while (c >= '0' && c <= '9') r = r * 10 + (c ^ 48), c = gc();
return rev ? ~r + 1 : r;
}
#endif
inline void push(const char& c) {
if (pp - pbuf == mxsz) fwrite(pbuf, 1, mxsz, stdout), pp = pbuf;
*pp++ = c;
}
inline void write(int x) {
static char sta[22]; int top = 0;
do sta[top++] = x % 10, x /= 10; while (x);
while (top) push(sta[--top] ^ 48);
}
inline void write(int x, char opc) {
#ifdef sopt
if (x < 0) push('-'), x = ~x + 1;
#endif
write(x), push(opc);
}
} io;
int n, a[300005], sz, mp[550][550], cnt[300005], vp[300005], mv[550][550];
vector<int> v[300005]; map<int, int>nid; int idx, tv[300005];
#define blk(i) ((i) / sz)
inline int sol(int l, int r, int t) {
return
upper_bound(v[t].begin(), v[t].end(), r) -
lower_bound(v[t].begin(), v[t].end(), l);
}
inline int query(int l, int r) {
int bl = blk(l), br = blk(r), ans = 0, ap = 0;
if (bl >= br - 1) {
for (int i = l; i <= r; i++) cnt[a[i]] = 0;
for (int i = l; i <= r; i++)
if (++cnt[a[i]] > ans) ans++, ap = a[i];
else if (cnt[a[i]] == ans && a[i] < ap) ap = a[i];
return tv[ap];
}
ap = mp[bl + 1][br - 1]; ans = mv[bl + 1][br - 1]; int np;
for (int i = l; i != (bl + 1) * sz; i++) {
np = vp[i];
if (np + ans < v[a[i]].size() && v[a[i]][np + ans] <= r)
for (;np + ans < v[a[i]].size() && v[a[i]][np + ans] <= r;++ans, ap = a[i]);
else if (np + ans - 1 < v[a[i]].size() && v[a[i]][np + ans - 1] <= r)
if (a[i] < ap) ap = a[i];
}
for (int i = br * sz; i <= r; i++) {
np = vp[i];
if (np - ans >= 0 && v[a[i]][np - ans] >= l)
for (np = vp[i];np - ans >= 0 && v[a[i]][np - ans] >= l;++ans, ap = a[i]);
else if (np - ans + 1 >= 0 && v[a[i]][np - ans + 1] >= l)
if (a[i] < ap) ap = a[i];
}
return tv[ap];
}
signed main() {
ios::sync_with_stdio(0);
sz = sqrt(n = io.read());
for (int i = 0; i != n; i++) nid[a[i] = io.read()] = 0;
for (auto& v : nid) v.second = ++idx, tv[idx] = v.first;
for (int i = 0; i != n; i++) a[i] = nid[a[i]];
for (int i = 0; i != n; i++)
v[a[i]].push_back(i), vp[i] = v[a[i]].size() - 1;
for (int i = 0; i <= blk(n - 1); i++) {
memset(cnt, 0, sizeof cnt);
for (int j = i; j <= blk(n - 1); j++) {
mp[i][j] = j ? mp[i][j - 1] : 0; mv[i][j] = j ? mv[i][j - 1] : 0;
for (int k = j * sz; k != (j + 1) * sz && k != n; k++)
if (++cnt[a[k]] > mv[i][j]) mv[i][j]++, mp[i][j] = a[k];
else if (cnt[a[k]] == mv[i][j] && a[k] < mp[i][j]) mp[i][j] = a[k];
}
}
for (int i = 1, l, r; i <= n; i++)
l = io.read(), r = io.read(),
io.write(query(l - 1, r - 1), '\n');
}