BZOJ 2821: 作诗(Poetize) | 分块

题目:

http://www.lydsy.com/JudgeOnline/problem.php?id=2821


 

分块.

预处理:

ans[i][j]表示i块到j块的答案;

cnt[i][j]表示i数前j块出现的次数

询问:

ret=l到r包含的整块部分答案,然后暴力处理块外的数出现次数.

我们发现关于每个数x以下情况可以影响到答案

1.x出现奇数次,整块中出现了正偶数次,ret--

2.x出现奇数次,整块中出现了奇数次,ret++

3.x出现偶数次,整块中出现了奇数次,ret++

而x在整块出现次数可以用cnt轻松的求出

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 100005
#define sq 320
using namespace std;
int cnt[N][sq],sum[N],n,c,m,S,s,bl[N],br[N],a[N],ans[sq][sq],lastans, vis[N];
void Init()
{
    for (int i=0;i<n;i++)
    if (i%S==0) br[s]=i-1,bl[++s]=i;
    br[s]=n-1,bl[s+1]=br[s+1]=n;
    for (int i=1;i<=s;i++)
    {
    for (int j=1;j<=c;j++)
        cnt[j][i]=cnt[j][i-1];
    for (int h=bl[i],t=br[i];h<=t;h++)
        cnt[a[h]][i]=++sum[a[h]];
    }
    memset(sum,0,sizeof(sum));
    for (int i=1;i<=s;i++)
    {
    int k=bl[i],tmp=0,t,c;
    for (int j=k;j<n;j++) sum[a[j]]=0;
    for (int j=i;j<=s;j++)
    {
        t=br[j];
        for (;k<=t;k++)
        {
        if (vis[a[k]]==i)
        {
            c=++sum[a[k]];
            if (c%2==0) tmp++;
            else tmp--;
        }
        else vis[a[k]]=i,sum[a[k]]=1;
        }
        ans[i][j]=tmp; 
    }
    }
    memset(vis,0,sizeof(vis));
}
int Query(int l,int r)
{
    if (r-l<2*S)
    {
    int tmp=0;
    for (int i=l;i<=r;i++)
        if (!vis[a[i]]) vis[a[i]]=1,sum[a[i]]=1;
        else ++sum[a[i]];
    for (int i=l;i<=r;i++)
        if (vis[a[i]])
        tmp+=!(sum[a[i]]%2),vis[a[i]]=0;
    return tmp;
    }
    int L=l/S+1,R=r/S+1;
    if (l==bl[L]) L--;
    if (r==br[R]) R++;
    int st=bl[R],ed=br[L],res=ans[L+1][R-1];
    for (int i=l;i<=ed;i++)
    if (!vis[a[i]]) vis[a[i]]=1,sum[a[i]]=1;
    else sum[a[i]]++;
    for (int i=st;i<=r;i++)
    if (!vis[a[i]]) vis[a[i]]=1,sum[a[i]]=1;
    else sum[a[i]]++;
    for (int i=l;i<=ed;i++)
    if (vis[a[i]])
    {
        int cnt1=sum[a[i]],cnt2=cnt[a[i]][R-1]-cnt[a[i]][L];
        if (cnt2>0 && cnt2%2==0 && cnt1%2==1) res--;
        if (cnt2==0 && cnt1%2==0) res++;
        if (cnt2%2==1 && cnt1%2==1) res++;
        sum[a[i]]=vis[a[i]]=0;
    }
    for (int i=st;i<=r;i++)
    if (vis[a[i]])
    {
        int cnt1=sum[a[i]],cnt2=cnt[a[i]][R-1]-cnt[a[i]][L];
        if (cnt2>0 && cnt2%2==0 && cnt1%2==1) res--;
        if (cnt2==0 && cnt1%2==0) res++;
        if (cnt2%2==1 && cnt1%2==1) res++;
        sum[a[i]]=vis[a[i]]=0;
    }
    return res;
}
int main()
{
    scanf("%d%d%d",&n,&c,&m);S=sqrt(n);
    for (int i=0;i<n;i++)
    scanf("%d",a+i);
    Init();
     for (int i=1,l,r;i<=m;i++)
    {
    scanf("%d%d",&l,&r);
    l=(l+lastans)%n+1;
    r=(r+lastans)%n+1;
    if (l>r) swap(l,r);
    printf("%d\n",lastans=Query(l-1,r-1));
    }
    return 0;
}

 

posted @ 2018-01-02 17:55  MSPqwq  阅读(160)  评论(0编辑  收藏  举报