1. 预处理块l到块r 之间的答案, 可以nsqrt(n) 预处理
2. 预处理颜色c在每一块之间的个数, 并求前缀和, 这样我们就能O(1)求每个数在块l到r之间的出现次数,可以O(c sqet(n))预处理
3. 对于询问, 中间的块之间用预处理的答案, 然后对于两头多出来的2sqrt(n)个数, 我们暴力处理它们出现次数, 并查询它在中间的块的出现次数, 发现最多查询2sqrt(n)次, 时间复杂度是正确的
总之分块就用以下神仙方法使复杂度平均, 我们能预处理的,空间开得下的都可以先搞出来
#include<bits/stdc++.h>
#define N 100050
using namespace std;
int read(){
int cnt=0; char ch=0;
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))cnt=cnt*10+(ch-'0'),ch=getchar();
return cnt;
}
int cnt,siz,sta[N];
int n,c,m,ans,tmp[N];
int a[N],vis[N];
int pos[N],L[N],R[N];
int S[N][320], Ans[320][320];
void Solve(int l){
memset(sta,0,sizeof(sta));
int k = 0;
for(int i=l;i<=cnt;i++){
int nowl = L[i], nowr = R[i];
for(int j = L[i]; j<=R[i]; j++){
if(sta[a[j]] & 1) k++;
else if(sta[a[j]]) k--;
sta[a[j]]++;
}
Ans[l][i] = k;
}
}
int Quary(int l,int r){
int posl = pos[l], posr = pos[r];
if(posl == posr || posl + 1 == posr){
int ans = 0;
for(int i=l;i<=r;i++){
if(sta[a[i]] & 1) ans ++;
else if(sta[a[i]]) ans --;
sta[a[i]] ++;
}
for(int i=l;i<=r;i++) sta[a[i]]--;
return ans;
}
else{
int ans = Ans[posl+1][posr-1];
int ret = 0;
for(int i=l;i<=R[posl];i++){
sta[a[i]] ++;
if(!vis[a[i]]) tmp[++ret] = a[i], vis[a[i]] = 1;
}
for(int i=L[posr];i<=r;i++){
sta[a[i]] ++;
if(!vis[a[i]]) tmp[++ret] = a[i], vis[a[i]] = 1;
}
for(int i=1;i<=ret;i++){
int now = tmp[i];
int x = S[now][posr-1] - S[now][posl];
if((x % 2 == 0) && x) ans--;
x += sta[now];
if(x % 2 == 0) ans ++;
}
for(int i=l;i<=R[posl];i++){
sta[a[i]]--; vis[a[i]] = 0;
}
for(int i=L[posr];i<=r;i++){
sta[a[i]]--; vis[a[i]] = 0;
}
return ans;
}
}
int main(){
n = read(), c = read(), m = read();
for(int i=1;i<=n;i++) a[i] = read();
siz = sqrt(n);
for(int i=1;i<=n;i++) pos[i] = (i-1)/siz + 1;
for(int i=1;i<=n;i+=siz) L[++cnt] = i, R[cnt] = i + siz - 1;
R[cnt] = n;
for(int i=1;i<=cnt;i++) Solve(i);
for(int i=1;i<=n;i++) S[a[i]][pos[i]]++;
for(int i=1;i<=cnt;i++)
for(int j=1;j<=c;j++)
S[j][i] += S[j][i-1];
memset(sta,0,sizeof(sta));
while(m--){
int l = read(), r = read();
l = (l+ans) % n + 1, r = (r+ans) % n + 1;
if(l>r) swap(l,r);
ans = Quary(l,r); printf("%d\n",ans);
} return 0;
}