题目描述
给定一个长度为 的序列,有
次询问。
每次询问一个区间内,"元素出现次数" 的第 大的 "出现次数"。
强制在线。
正解
如果可以离线,有一个经典的莫队 + 值域分块做法可以做到严格 。(而且常数很小
就直接暴力移动左右端点,移动端点的修改复杂度是 的,然后单次查询是
的。
考虑在线怎么用莫队做。
预处理一些 的桶和分块数组,然后查寻就从最近的
开始移动,查寻完后还原桶和分块数组。
其实可以预处理很多 的,但由于空间原因,最多就只能预处理
个。
然后一次询问就需要移动大约 3000 次,总的复杂度有 ,实现精细一点应该可以通过。
代码
#pragma GCC optimize("O2")
#include <bits/stdc++.h>
#define N 100005
using namespace std;
const int B1 = 1000, B2 = 1400;
int n, m, type;
int a[N];
int L[600], R[600];
int rec[600][N], f[600][N], g[600][B1];
int bel[N], bl[105], br[105];
inline int read() {
int x = 0; char ch = getchar();
while(!isdigit(ch)) ch = getchar();
while(isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
return x;
}
void getFunc(int l, int r, int *rec, int *f, int *g) {
f[0] = n, g[0] = n;
for(int i = l; i <= r; ++i) {
--f[rec[a[i]]], --g[bel[rec[a[i]]]];
++rec[a[i]];
++f[rec[a[i]]], ++g[bel[rec[a[i]]]];
}
}
void move(int l, int r, int ll, int rr, int *rec, int *f, int *g) {
register int *lp = a + l, *rp = a + r, c;
while(l > ll) {
--lp, --l, c = ++rec[*lp];
--f[c - 1], --g[bel[c - 1]];
++f[c], ++g[bel[c]];
}
while(r < rr) {
++rp, ++r, c = ++rec[*rp];
--f[c - 1], --g[bel[c - 1]];
++f[c], ++g[bel[c]];
}
while(l < ll) {
c = rec[*lp]--, ++lp, ++l;
--f[c], --g[bel[c]];
++f[c - 1], ++g[bel[c - 1]];
}
while(r > rr) {
c = rec[*rp]--, --rp, --r;
--f[c], --g[bel[c]];
++f[c - 1], ++g[bel[c - 1]];
}
}
int getAns(int *f, int *g, int rem) {
if(rem > n) return 0;
for(int i = bel[n]; ~i; --i) {
if(rem > g[i]) {
rem -= g[i];
} else {
for(int j = br[i]; j >= bl[i]; --j) {
rem -= f[j];
if(rem <= 0) return j;
}
}
}
return -1;
}
int main() {
n = read(), m = read(), type = read();
for(int i = 1; i <= n; ++i) a[i] = read();
for(int i = 0; i <= n; ++i)
bel[i] = i / B1;
for(int i = 0; i <= n; ++i)
br[bel[i]] = i;
for(int i = n; i >= 0; --i)
bl[bel[i]] = i;
int c = 0;
f[0][0] = g[0][0] = n;
for(int l = B2; l <= n; l += (B2 << 1))
for(int r = l + (B2 << 1); r <= n; r += (B2 << 1)) {
if(r - l <= (B2 << 1)) continue;
++c, L[c] = l, R[c] = r;
getFunc(l, r, rec[c], f[c], g[c]);
}
int ans = 0, cnt = 0, o;
for(int Case = 1, l, r, k; Case <= m; ++Case) {
l = read(), r = read(), k = read();
if(type & 1) l = l ^ ans, r = r ^ ans, k = k ^ ans;
if(r - l <= (B2 << 1)) {
++cnt;
move(l, l - 1, l, r, rec[0], f[0], g[0]);
ans = getAns(f[0], g[0], k);
move(l, r, l, l - 1, rec[0], f[0], g[0]);
} else {
o = 0;
for(int i = 1; i <= c; ++i)
if(!o || abs(l - L[i]) + abs(r - R[i]) < abs(l - L[o]) + abs(r - R[o]))
o = i;
move(L[o], R[o], l, r, rec[o], f[o], g[o]);
ans = getAns(f[o], g[o], k);
move(l, r, L[o], R[o], rec[o], f[o], g[o]);
}
printf("%d\n", ans);
}
return 0;
} 
京公网安备 11010502036488号