P4168 [Violet]蒲公英
题目链接
分块。
一看到这数据范围肯定要离散化。而且强制在线,不可用莫队做。
(p[i][j])表示第(i)个块到第(j)个块内的众数,预处理出来就好了,枚举(i)和(j)是(O(sqrt n))的,枚举(j)块内的数也是(O(sqrt n))的,总复杂度(O(nsqrt n))。
(sum[i][h])表示前(i)个块数字(h)出现的个数,预处理是(O(n))的。
对于每一个查询,假设左端点(l)所在的块是(x),右端点(r)所在的块是(y),然后分情况:
如果(y - x <= 2),直接暴力,最多扫(3 *sqrt n)个数,复杂度(O( sqrt n))。
如果(y - x > 2),我们可以确定这个众数一定出现在两边的残块中或中间的整块中,我们只需枚举残块中的每个数,用预处理出来的(sum)数组求出整个区间某个数的个数,最后在与(p[x + 1][y - 1]),比较一下就好了,最多扫(2 *sqrt n)个数,复杂度(O( sqrt n))。
#include <bits/stdc++.h>
using namespace std;
inline long long read() {
long long s = 0, f = 1; char ch;
while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
return s * f;
}
const int N = 4e4 + 5;
int n, m, t, len, last;
int a[N], c[N], vis[N], pos[N], tong[N], pre[N], sum[205][N];
struct block { int l, r; } b[N];
struct number { int num, x; } p[205][205];
void make_pre() {
for(int i = 1;i <= t; i++) {
number tmp; tmp.num = tmp.x = 0;
for(int j = i;j <= t; j++) {
for(int k = b[j].l;k <= b[j].r; k++) {
tong[a[k]]++;
if(tong[a[k]] > tmp.num) {
tmp.num = tong[a[k]]; tmp.x = a[k];
}
else if(tong[a[k]] == tmp.num) {
tmp.x = min(tmp.x, a[k]);
}
}
p[i][j] = tmp;
}
for(int j = i;j <= t; j++)
for(int k = b[j].l;k <= b[j].r; k++) tong[a[k]] = 0;
}
for(int i = 1;i <= t; i++) {
for(int j = 1;j <= n; j++) sum[i][a[j]] = sum[i - 1][a[j]];
for(int j = b[i].l;j <= b[i].r; j++) sum[i][a[j]] ++;
}
}
int query(int l, int r) {
int x = pos[l], y = pos[r];
if(y - x <= 2) {
int tmp = 0;
for(int i = l;i <= r; i++) tong[a[i]] = 0;
for(int i = l;i <= r; i++) {
tong[a[i]] ++;
if(tong[a[i]] > tong[tmp]) tmp = a[i];
else if(tong[a[i]] == tong[tmp]) tmp = min(tmp, a[i]);
}
return pre[tmp];
}
else {
int ans = p[x + 1][y - 1].x, res_num = 0, res_x = 0;
tong[ans] = vis[ans] = 0;
for(int i = l;i <= b[x].r; i++) tong[a[i]] = 0, vis[a[i]] = 0;
for(int i = b[y].l;i <= r; i++) tong[a[i]] = 0, vis[a[i]] = 0;
for(int i = l;i <= b[x].r; i++) tong[a[i]] ++;
for(int i = b[y].l;i <= r; i++) tong[a[i]] ++;
for(int i = l;i <= b[x].r; i++) {
if(!vis[a[i]]) {
vis[a[i]] = 1;
int tmp = tong[a[i]] + sum[y - 1][a[i]] - sum[x][a[i]];
if(res_num < tmp) res_num = tmp, res_x = a[i];
else if(res_num == tmp) res_x = min(res_x, a[i]);
}
}
for(int i = b[y].l;i <= r; i++) {
if(!vis[a[i]]) {
vis[a[i]] = 1;
int tmp = tong[a[i]] + sum[y - 1][a[i]] - sum[x][a[i]];
if(res_num < tmp) res_num = tmp, res_x = a[i];
else if(res_num == tmp) res_x = min(res_x, a[i]);
}
}
int tmp = tong[ans] + p[x + 1][y - 1].num;
if(res_num > tmp) ans = res_x;
else if(res_num == tmp) ans = min(ans, res_x);
return pre[ans];
}
}
int main() {
n = read(); m = read(); len = sqrt(n); t = (n - 1) / len + 1;
for(int i = 1;i <= n; i++) a[i] = c[i] = read(), pos[i] = (i - 1) / len + 1, b[pos[i]].l = 2333333;
for(int i = 1;i <= n; i++) b[pos[i]].l = min(b[pos[i]].l, i), b[pos[i]].r = max(b[pos[i]].r, i);
sort(c + 1, c + n + 1);
int cnt = unique(c + 1, c + n + 1) - c - 1;
for(int i = 1;i <= n; i++) {
int tmp = a[i];
a[i] = lower_bound(c + 1, c + cnt + 1, a[i]) - c;
pre[a[i]] = tmp;
}
make_pre();
for(int i = 1, l, r;i <= m; i++) {
l = read(); r = read();
l = (last + l - 1) % n + 1; r = (last + r - 1) % n + 1;
if(l > r) swap(l, r);
printf("%d
", last = query(l, r));
}
return 0;
}