[bzoj] 2821 作诗(Poetize) || 分块
原题
求[l,r]中有多少个数出现过正偶数次
分块板子题。
预处理cnt[i][j]和f[i][j],cnt[i][j]记录i在前j块出现的次数,f[i][j]表示i块到j块的答案。
每次询问,整块的给出答案后,暴力非整块,对于非整块的答案有三种特判来判断是否答案++:
1、整块中没出现,非整块出现偶数次,则++
2、整块出现偶数次,非整块出现奇数次,则--
3、整块出现奇数次,非整块出现奇数次,则++
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 100010
#define B 319
#define inf 0x3f3f3f3f
using namespace std;
int n,m,num,s,l,r,ans,a[N],sum[N],idx;
int bl[B],br[B],f[B][B],cnt[N][B];
bool v[N];
int read()
{
int ans=0,fu=1;
char j=getchar();
for (;j<'0' || j>'9';j=getchar()) if (j=='-') fu=-1;
for (;j>='0' && j<='9';j=getchar()) ans*=10,ans+=j-'0';
return ans*fu;
}
void init()
{
int k,t,h,c,ans=0;
for (int i=1;i<=s;i++)
{
ans=0;
k=bl[i];
for (int j=k;j<n;j++)
sum[a[j]]=0;
for (int j=i;j<=s;j++)
{
t=br[j];
while (k<=t)
{
c=++sum[a[k]];
if (c%2) ans--;
else ans++;
++k;
}
f[i][j]=ans;
}
}
memset(sum,0,sizeof(sum));
for (int i=1;i<=s;i++)
{
for (int j=0;j<idx;j++) cnt[j][i]=cnt[j][i-1];
h=bl[i];
t=br[i];
while (h<=t) cnt[a[h]][i]=++sum[a[h]],++h;
}
}
int query(int l,int r)
{
int ret=0,c;
if (r-l<2*s)
{
for (int i=l;i<=r;i++)
if (!v[a[i]]) v[a[i]]=1,sum[a[i]]=1;
else ++sum[a[i]];
for (int i=l;i<=r;i++)
if (v[a[i]])
{
if (sum[a[i]]%2==0) ret++;
v[a[i]]=0;
}
return ret;
}
int L=l/num+1,R=r/num+1,st,en;
if (l==bl[L]) --L;
if (r==br[R]) ++R;
en=br[L];st=bl[R];
for (int i=l;i<=en;i++)
if (!v[a[i]]) v[a[i]]=1,sum[a[i]]=1;
else ++sum[a[i]];
for (int i=st;i<=r;i++)
if (!v[a[i]]) v[a[i]]=1,sum[a[i]]=1;
else ++sum[a[i]];
for (int i=1;i<=idx;i++)
if (!v[i] && (cnt[i][R-1]-cnt[i][L])%2==0) ret++;
for (int i=l;i<=en;i++)
if (v[a[i]])
{
c=cnt[a[i]][R-1]-cnt[a[i]][L];
c+=sum[a[i]];
if (c%2==0) ret++;
v[a[i]]=0;
}
for (int i=st;i<=r;i++)
if (v[a[i]])
{
c=cnt[a[i]][R-1]-cnt[a[i]][L];
c+=sum[a[i]];
if (c%2==0) ret++;
v[a[i]]=0;
}
return ret;
}
int main()
{
n=read();
idx=read();
m=read();
for (int i=0;i<n;i++) a[i]=read();
num=sqrt(n);
for (int i=0;i<n;i++)
if (i%num==0) br[s]=i-1,bl[++s]=i;
br[s]=n-1;
bl[s+1]=br[s+1]=n;
init();
while (m--)
{
l=read();r=read();
l=(l+ans)%n;
r=(r+ans)%n;
if (l>r) swap(l,r);
printf("%d\n",ans=query(l,r));
}
return 0;
}