分块
分sqrt(n)块
F[i][j]表示块i到块j的答案
s[i][j]表示数字i在前j块内出现了几次
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#define N 100005
#define M 233
#define L(x) (n*((x)-1)/m+1)
#define R(x) (n*(x)/m)
using namespace std;
inline int read(){
int ret=0;char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while ('0'<=ch&&ch<='9'){
ret=ret*10-48+ch;
ch=getchar();
}
return ret;
}
int n,a[N],l;
int bl[N],m;
int F[M][M];
int s[N][M];
int cnt[N];
void precompute(){
m=min((int)sqrt(n),230);
memset(cnt,0,sizeof(cnt));
for (int i=1;i<=m;++i){
for (int j=L(i);j<=R(i);++j){
bl[j]=i;++cnt[a[j]];
}
for (int j=1;j<=l;++j) s[j][i]=cnt[j];
}
memset(F,0,sizeof(F));
for (int i=1;i<=m;++i){
memset(cnt,0,sizeof(cnt));
int now=0;
for (int j=i;j<=m;++j){
for (int k=L(j);k<=R(j);++k){
if ((++cnt[a[k]])<2) continue;
now-=(cnt[a[k]]&1)*2-1;
}
F[i][j]=now;
}
}
memset(cnt,0,sizeof(cnt));
}
int query(int l,int r){
int now=F[bl[l]+1][bl[r]-1];
if (bl[l]==bl[r]){
for (int i=l;i<=r;++i){
if ((++cnt[a[i]])<2) continue;
now-=(cnt[a[i]]&1)*2-1;
}
for (int i=l;i<=r;++i) --cnt[a[i]];
return now;
}
for (int i=l;i<=r;i=(i==R(bl[l])?L(bl[r]):(i+1))){
if ((++cnt[a[i]])+s[a[i]][bl[r]-1]-s[a[i]][bl[l]]<2) continue;
now-=((cnt[a[i]]+s[a[i]][bl[r]-1]-s[a[i]][bl[l]])&1)*2-1;
}
for (int i=l;i<=r;i=(i==R(bl[l])?L(bl[r]):(i+1))) --cnt[a[i]];
return now;
}
int main(){
n=read();l=read();int Q=read(),ans=0;
for (int i=1;i<=n;++i) a[i]=read();
precompute();
while (Q--){
int x=(read()+ans)%n+1,y=(read()+ans)%n+1;
printf("%d\n",ans=query(min(x,y),max(x,y)));
}
return 0;
}