「Ynoi2019 模拟赛」Yuno loves sqrt technology III
区间众数。
发现如果可以离线莫队特别好做,那按理来说莫队能做的分块都能做,所以考虑分块。
做分块就先考虑一些经典东西:\(val_{i, j}\) 表示块 \(i\) 到块 \(j\) 的众数出现次数。
对于查询 \([l, r]\),我们已经获取了块 \([bel_l + 1, bel_r - 1]\) 的众数出现次数 \(cnt\),发掘该信息对答案有什么用,因为只剩下 \(2 \sqrt{N}\) 个数没统计,那么答案最多比 \(cnt\) 多 \(2 \sqrt{N}\),且若比答案更大,众数一定出现在没统计到的数中,即块 \(bel_l\),\(bel_r\) 中没被统计的数,然后我们对于某个数可以 \(O(1)\) check该数在区间内出现次数与答案大小关系,用 \(O(V)\) 个vector存下每种值的出现位置,记 \(p_v\) 按顺序存下值 \(v\) 的所有出现位置,假设当前位置为 \(p_{v, i}\),直接看 \(p_{v, i + ans - 1}\) 是否 \(\leq r\) 即可 check。
然后因为答案 \(\in [cnt, cnt + 2 \sqrt{N}]\),所以答案最多只会被 check 成功 \(2\sqrt{N}\) 次,而两边散块每个可能的众数只会 check 失败 \(1\) 次,总计最多 \(2 \sqrt{N}\) 次,所以先将 \(ans\) 设为 \(cnt\),暴力对两边散块 check \(ans + 1\),check 成功就将 \(ans\) 加一,时间复杂度 \(O(N \sqrt{N})\),空间复杂度 \(O(N)\)。
/*
address:https://www.luogu.com.cn/problem/P5048
AC 2026/9/2 21:07
*/
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5 + 5;
const int S = 710;
int n, q, a[N], disc[N], m;
inline void read(int& x) {
x = 0;
char c = getchar();
while (c < '0' || c > '9') c = getchar();
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
}
vector<int>vec[N];
int rnk[N];
int lastans;
int val[S][S];
int bel[N], L[S], R[S];
int siz, blk;
int cnt[N];
bool vis[N];
int main() {
read(n), read(q);
for (int i = 1;i <= n;++i) read(a[i]), disc[++m] = a[i];
sort(disc + 1, disc + m + 1);
m = unique(disc + 1, disc + m + 1) - disc - 1;
for (int i = 1;i <= m;++i) vec[i].push_back(0);
for (int i = 1;i <= n;++i) vec[a[i] = lower_bound(disc + 1, disc + m + 1, a[i]) - disc].push_back(i), rnk[i] = vec[a[i]].size() - 1;
for (int i = 1;i <= m;++i) vec[i].push_back(n + 1);
siz = sqrt(n);
blk = (n + siz - 1) / siz;
for (int i = 1;i <= n;++i) bel[i] = (i + siz - 1) / siz;
for (int i = 1;i <= blk;++i) L[i] = (i - 1) * siz + 1, R[i] = min(n, i * siz);
for (int i = 1;i <= blk;++i) {
for (int j = 1;j <= m;++j) cnt[j] = 0;
for (int j = 0;j <= n;++j) vis[j] = false;
int cur = 0;
for (int j = i;j <= blk;++j) {
for (int k = L[j];k <= R[j];++k) {
vis[++cnt[a[k]]] = true;
if (vis[cur + 1]) ++cur;
}
val[i][j] = cur;
}
}
while (q--) {
int l, r;read(l), read(r);
l ^= lastans, r ^= lastans;
int p = bel[l], q = bel[r];
if (p + 1 >= q) {
lastans = 0;
for (int i = l;i <= r;++i) cnt[a[i]] = 0;
for (int i = 0;i <= r - l + 1;++i) vis[i] = false;
for (int i = l;i <= r;++i) {
vis[++cnt[a[i]]] = true;
if (vis[lastans + 1]) ++lastans;
}
}
else {
lastans = val[p + 1][q - 1];
for (int i = l;i <= R[p];++i)
if (rnk[i] + lastans < vec[a[i]].size())
while (vec[a[i]][rnk[i] + lastans] <= r) ++lastans;
for (int i = L[q];i <= r;++i)
if (rnk[i] - lastans >= 0)
while (vec[a[i]][rnk[i] - lastans] >= l) ++lastans;
}
printf("%d\n", lastans);
}
return 0;
}

浙公网安备 33010602011771号