这道题真的恶心,我花了一上午的时间才A。
对比了一下其他人的代码,我感觉自己的代码十分冗长。
分块肯定是要的,分块完以后处理一下块中各种花的前缀和,并对于同种花在同一个块内搞一个倍增,这样可以快速的找出同种花的个数。顺便记录每一个块开头到任意一个点的众数。
查询的时候只需要找左边不在整块内的花,然后用倍增和前缀和查找出所有同种类的花,然后比较最大值。
上面有很多细节已经省略,请看代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 4e4 + 10, M = 5e4 + 10, K = 210;
int n, m, q, a[N], b[N];
int get(int x) {
int l = 1, r = m, mid, ans;
while (l <= r) {
mid = (l + r) >> 1;
if (b[mid] <= x) ans = mid, l = mid + 1;
else r = mid - 1;
}
return ans;
}
int cnt, L[K], R[K], p[N];
//s[K][N] 前缀和
//nxt[N][10] 倍增
//head[K][N] 块中第一个
//zs[K][N] 块头到某个点的众数,num[K][N]个数
int s[K][N], nxt[N][10], head[K][N], zs[K][N], num[K][N];
int last[N], sum[N];
bool vis[N]; int tp, sta[N];
int getl(int now) {
int sum = 1;
for (int j = 8; j >= 0; j--)
if (nxt[now][j]) now = nxt[now][j], sum += (1 << j);
return sum;
}
int getr(int now, int y) {
if (!now || now > y) return 0;
int sum = 1, p = 1;
while (p > 0) {
if (!nxt[now][p - 1]) p--;
else {
if (nxt[now][p - 1] <= y) now = nxt[now][p - 1], sum += 1 << (p - 1), p++;
else p--;
}
}
return sum;
}
int main() {
freopen("2.in", "r", stdin);
cin >> n >> q;
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
b[i] = a[i];
}
sort(b + 1, b + n + 1); m = 1;
for (int i = 2; i <= n; i++)
if (b[i] != b[i - 1]) b[++m] = b[i];
for (int i = 1; i <= n; i++) a[i] = get(a[i]);
int block = 3, cnt = (n - 1) / block + 1;
for (int i = 1; i <= cnt; i++) {
L[i] = R[i - 1] + 1;
R[i] = R[i - 1] + block;
if (i == cnt) R[i] = n;
for (int j = L[i]; j <= R[i]; j++) p[j] = i;
}
for (int i = 1; i <= cnt; i++) {
for (int j = 1; j <= m; j++) s[i][j] = s[i - 1][j], last[j] = sum[j] = 0;
for (int j = L[i]; j <= R[i]; j++) {
s[i][a[j]]++;
if (head[i][a[j]] == 0) head[i][a[j]] = j;
if (last[a[j]]) nxt[last[a[j]]][0] = j;
last[a[j]] = j;
}
int maxx = 0;
for (int j = L[i]; j <= n; j++) {
sum[a[j]]++;
if ((sum[a[j]] > sum[maxx]) || (sum[a[j]] == sum[maxx] && a[j] < maxx)) maxx = a[j];
zs[i][j] = maxx; num[i][j] = sum[maxx];
}
}
for (int j = 1; j <= 8; j++)
for (int i = 1; i <= n; i++)
nxt[i][j] = nxt[nxt[i][j - 1]][j - 1];
int lastans = 0;
for (int i = 1; i <= q; i++) {
int x, y; scanf("%d%d", &x, &y);
x = (x + lastans - 1) % n + 1;
y = (y + lastans - 1) % n + 1;
if (x > y) swap(x, y);
int l = L[p[x]] == x ? p[x] : p[x] + 1;
int r = R[p[y]] == y ? p[y] : p[y] - 1;
if (l > r) {
int maxx = 0, hh;
if (p[x] == p[y]) {
for (int i = x; i <= y; i++)
if (!vis[a[i]]) {
vis[a[i]] = 1; sta[++tp] = a[i];
int now = i, sum = getr(now, y);
if (sum > maxx || (sum == maxx && hh > a[i])) maxx = sum, hh = a[i];
}
}
else {
for (int i = x; i <= y; i++) {
if (vis[a[i]]) continue;
vis[a[i]] = 1; sta[++tp] = a[i];
int sum = 0, now = i;
if (i <= R[p[x]]) sum += getl(now);
now = head[p[y]][a[i]];
sum += getr(now, y);
if (sum > maxx || (sum == maxx && hh > a[i])) maxx = sum, hh = a[i];
}
}
printf("%d\n", lastans = b[hh]);
}
else {
int p1 = zs[l][y], s1 = num[l][y];
if (L[p[x]] == x) { printf("%d\n", lastans = b[p1]); continue;}
int maxx = 0, hh;
for (int i = x; i < L[l]; i++) {
if (vis[a[i]]) continue;
if (a[i] == p1) {s1++; continue;}
vis[a[i]] = 1; sta[++tp] = a[i];
int sum = s[r][a[i]] - s[l - 1][a[i]], now;
now = i; sum += getl(now);
if (y != R[p[y]]) now = head[p[y]][a[i]], sum += getr(now, y);
if (sum > maxx || (sum == maxx && hh > a[i])) maxx = sum, hh = a[i];
}
if (s1 > maxx || (s1 == maxx && p1 < hh)) printf("%d\n", lastans = b[p1]);
else printf("%d\n", lastans = b[hh]);
}
while (tp) vis[sta[tp--]] = 0;
}
return 0;
}