【题目链接】
【前置技能】
- 分块
【题解】
- 题意:有一个长度为 的序列 ,其中 , 组询问,每次询问区间 中出现正偶数次的数的种类数,强制在线。
- 数据范围:
- 首先,这道题不强制在线怎么做呢?莫队。
- 似乎强制在线之后就不太好做了,怎么办呢?分块大法好。
- 先预处理出每一段连续的整块的答案,即整块 以及之间的整块的答案。枚举最左边的整块,暴力统计个数和答案即可。还要预处理出到每一个整块的末尾处每个数有多少个。从头开始统计,到块的末尾处记下数组即可。
- 每次询问的时候,若 和 在同一块中,暴力处理即可,注意数组不能memset。若不在同一块中,我们先将答案记为中间整块的答案,对于旁边的散块,将其中的数记下来,统计一下每种数的个数。利用我们预处理出的第二个数组求出整块内每种数的个数,结合散块中的每种数的个数,对答案进行调整。
- 在 同阶的情况下,时间复杂度 ,当 取 时为
- 本题这种做法的空间卡得有点紧,数组不能多开太多。
【代码】
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define LL long long
#define MAXN 100010
#define MAXM 320
using namespace std;
int belong[MAXN], lb[MAXM], rb[MAXM];
int n, m, c, lastans, k, tot, w[MAXN], a[MAXM][MAXM], cnt[MAXN], b[MAXM][MAXN], tmp[MAXM * 2], cmt;
vector <int> used;
template <typename T> void chkmin(T &x, T y){x = min(x, y);}
template <typename T> void chkmax(T &x, T y){x = max(x, y);}
template <typename T> void read(T &x){
x = 0; int f = 1; char ch = getchar();
while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}
while (isdigit(ch)) {x = x * 10 + ch - '0'; ch = getchar();}
x *= f;
}
int main(){
read(n), read(c), read(m);
for (int i = 1; i <= n; ++i)
read(w[i]);
k = (int)(sqrt(n) + 0.5);
for (int i = 1; i <= n; ++i){
if (i % k == 1) ++tot, lb[tot] = i, rb[tot - 1] = i - 1;
belong[i] = tot;
}
rb[tot] = n;
for (int i = 1; i <= tot; ++i){
memset(cnt, 0, sizeof(cnt));
int ans = 0;
for (int j = i; j <= tot; ++j){
for (int t = lb[j]; t <= rb[j]; ++t){
++cnt[w[t]];
if (cnt[w[t]] == 1) continue;
if (cnt[w[t]] % 2 == 0) ++ans; else --ans;
}
a[i][j] = ans;
}
}
memset(cnt, 0, sizeof(cnt));
for (int i = 1; i <= tot; ++i){
for (int j = lb[i]; j <= rb[i]; ++j)
++cnt[w[j]];
for (int j = 1; j <= c; ++j)
b[i][j] = cnt[j];
}
memset(cnt, 0, sizeof(cnt));
while (m--){
int l, r; read(l), read(r);
l = (l + lastans) % n + 1, r = (r + lastans) % n + 1;
if (l > r) swap(l, r);
lastans = 0;
if (r - l + 1 < 2 * k) {
for (int i = l; i <= r; ++i){
++cnt[w[i]];
if (cnt[w[i]] == 1) continue;
if (cnt[w[i]] % 2 == 0) ++lastans; else --lastans;
}
for (int i = l; i <= r; ++i)
--cnt[w[i]];
} else {
int L = belong[l], R = belong[r];
if (l != lb[L]) ++L; if (r != rb[R]) --R;
lastans = a[L][R];
cmt = 0;
for (int i = l; i < lb[L]; ++i)
tmp[++cmt] = w[i];
for (int i = rb[R] + 1; i <= r; ++i)
tmp[++cmt] = w[i];
for (int i = 1; i <= cmt; ++i){
if (!cnt[tmp[i]]) used.push_back(tmp[i]);
++cnt[tmp[i]];
}
for (int i = 0, si = used.size(); i < si; ++i){
int x = cnt[used[i]], y = b[R][used[i]] - b[L - 1][used[i]];
if (y == 0){
if (x % 2 == 0) ++lastans;
} else {
if (x % 2 == 1){
if (y % 2 == 0) --lastans;
else ++lastans;
}
}
}
for (int i = 1; i <= cmt; ++i)
--cnt[tmp[i]];
used.clear();
}
printf("%d\n", lastans);
}
return 0;
}