参考
题意:给定数列,mm次询问
[
l
i
,
r
i
]
[l_i,r_i]
[li?,ri?]中,出现正偶数次的数的个数。
idea:之前我们是做过问区间众数的题的,这题跟那题比较类似,但不完全相同。我们需要预处理出
c
n
t
[
i
]
[
j
]
cnt[i][j]
cnt[i][j] 为前
i
i
i块中
j
j
j出现的次数,
a
n
s
[
i
]
[
j
]
ans[i][j]
ans[i][j]为第
i
i
i块到第
j
j
j块中出现偶数次的数的个数
ACcode:
#include<iostream>
#include<cstring>
#include<cstdio>
#define LL long long
#include<cmath>
#define N 100010
#define SQ 1010
using namespace std;
int n,m,c,cnt[SQ][N],ans[SQ][SQ],val[N],bl[N],st[SQ],ed[SQ],maxx=-1,t[N],sq;
void init()
{
for(int i=1;i<=bl[n];i++)
{
st[i] = (i-1)*sq + 1;
ed[i] = i*sq ;
}
ed[ bl[n] ] = n;
for(int i=1;i<=bl[n];i++)
{
for(int j=0;j<=c;j++)
{
cnt[i][j] += cnt[i-1][j];
}
}
for(int i=1;i<=bl[n];i++)
{
for(int j=i;j<=bl[n];j++)
{
ans[i][j] = ans[i][j-1];
for(int k=st[j];k<=ed[j];k++)
{
t[ val[k] ]++;
if( t[ val[k] ]%2==0 ) ans[i][j]++;
else if( t[ val[k] ]>=3 ) ans[i][j]--;
}
}
memset(t,0,sizeof(t));
}
}
int query(int l,int r)
{
int sum = 0;
if( bl[l]+1>=bl[r] )
{
for(int i=l;i<=r;i++)
{
t[ val[i] ]++;
if( t[ val[i] ]%2==0 ) sum++;
else if( t[ val[i] ]>=3 ) sum--;
}
for(int i=l;i<=r;i++) t[ val[i] ]--;
return sum;
}
sum = ans[ bl[l]+1 ][ bl[r]-1 ];
for(int i=l;i<=min( r,ed[ bl[l] ] );i++)
{
t[ val[i] ]++;
int v = cnt[ bl[r]-1 ][ val[i] ] - cnt[ bl[l] ][ val[i] ];
if( (t[ val[i] ]+v)%2==0 ) sum++;
else if( (t[ val[i] ]+v)>=3 ) sum--;
}
if( bl[l] != bl[r] )
{
for(int i=st[ bl[r] ];i<=r;i++)
{
t[ val[i] ]++;
int v = cnt[ bl[r]-1 ][ val[i] ] - cnt[ bl[l] ][ val[i] ];
if( (t[ val[i] ]+v)%2==0 ) sum++;
else if( t[ val[i] ]+v >=3 ) sum--;
}
for(int i=st[ bl[r] ];i<=r;i++) t[ val[i] ]--;
}
for(int i=l;i<=min( r,ed[bl[l]] );i++) t[ val[i] ]--;
return sum;
}
void solve()
{
scanf("%d %d %d",&n,&c,&m);
sq = sqrt(n);
for(int i=1;i<=n;i++)
{
scanf("%d",&val[i]);
bl[i] = (i-1)/sq + 1;
cnt[ bl[i] ][ val[i] ]++;
}
init();
int as = 0;
while( m-- )
{
int l,r;
scanf("%d %d",&l,&r);
l = (l+as) % n + 1;
r = (r+as) % n + 1;
if( l>r ) swap( l,r );
as = query( l,r );
printf("%d\n",as);
}
}
signed main()
{
solve();
return 0;
}
|