[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;
}
posted @ 2018-01-03 20:10  Mrha  阅读(196)  评论(0编辑  收藏  举报