询问区间出现次数为正偶数的数的个数
经典分块方法。
预处理ans[i,j]表示第i块到第j块的答案,sum[i,j]表示前j块中元素i出现的次数。
然后搞一波就行了。
bzoj上空限卡得比较蛋疼。
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=100000+10;
int cnt[maxn],a[maxn],belong[maxn];
int sum[maxn][320],ans[320][320];
int i,j,k,l,r,t,n,m,c,now;
int main(){
scanf("%d%d%d",&n,&m,&m);
fo(i,1,n) scanf("%d",&a[i]);
c=floor(sqrt(n))+1;
fo(i,1,n) belong[i]=(i-1)/c+1;
fo(i,1,n)
sum[a[i]][belong[i]]++;
fo(i,1,100000)
fo(j,1,belong[n])
sum[i][j]+=sum[i][j-1];
fo(i,1,belong[n]){
now=0;
fo(j,(i-1)*c+1,n){
cnt[a[j]]++;
if (cnt[a[j]]&&cnt[a[j]]%2==0) now++;
else if (cnt[a[j]]>2) now--;
ans[i][belong[j]]=now;
}
fo(j,(i-1)*c+1,n) cnt[a[j]]--;
}
now=0;
while (m--){
scanf("%d%d",&j,&k);
j=(j+now)%n+1;k=(k+now)%n+1;
if (j>k) swap(j,k);
l=belong[j];r=belong[k];
if (r-l<=1){
now=0;
fo(i,j,k){
cnt[a[i]]++;
if (cnt[a[i]]&&cnt[a[i]]%2==0) now++;
else if (cnt[a[i]]>2) now--;
}
fo(i,j,k) cnt[a[i]]--;
printf("%d\n",now);
continue;
}
now=ans[l+1][r-1];
fo(i,j,l*c){
cnt[a[i]]++;
if (cnt[a[i]]+sum[a[i]][r-1]-sum[a[i]][l]&&(cnt[a[i]]+sum[a[i]][r-1]-sum[a[i]][l])%2==0) now++;
else if (cnt[a[i]]+sum[a[i]][r-1]-sum[a[i]][l]>2) now--;
}
fo(i,(r-1)*c+1,k){
cnt[a[i]]++;
if (cnt[a[i]]+sum[a[i]][r-1]-sum[a[i]][l]&&(cnt[a[i]]+sum[a[i]][r-1]-sum[a[i]][l])%2==0) now++;
else if (cnt[a[i]]+sum[a[i]][r-1]-sum[a[i]][l]>2) now--;
}
printf("%d\n",now);
fo(i,j,l*c) cnt[a[i]]--;
fo(i,(r-1)*c+1,k) cnt[a[i]]--;
}
}