BZOJ2821 作诗(Poetize) 【分块】

BZOJ2821 作诗(Poetize)


Description

神犇SJY虐完HEOI之后给傻×LYD出了一题:
SHY是T国的公主,平时的一大爱好是作诗。
由于时间紧迫,SHY作完诗之后还要虐OI,于是SHY找来一篇长度为N的文章,阅读M次,每次只阅读其中连续的一段[l,r],从这一段中选出一些汉字构成诗。因为SHY喜欢对偶,所以SHY规定最后选出的每个汉字都必须在[l,r]里出现了正偶数次。而且SHY认为选出的汉字的种类数(两个一样的汉字称为同一种)越多越好(为了拿到更多的素材!)。于是SHY请LYD安排选法。
LYD这种傻×当然不会了,于是向你请教……
问题简述:N个数,M组询问,每次问[l,r]中有多少个数出现正偶数次。

Input

输入第一行三个整数n、c以及m。表示文章字数、汉字的种类数、要选择M次。
第二行有n个整数,每个数Ai在[1, c]间,代表一个编码为Ai的汉字。
接下来m行每行两个整数l和r,设上一个询问的答案为ans(第一个询问时ans=0),令L=(l+ans)mod n+1, R=(r+ans)mod n+1,若L>R,交换L和R,则本次询问为[L,R]。

Output
输出共m行,每行一个整数,第i个数表示SHY第i次能选出的汉字的最多种类数。

Sample Input

5 3 5
1 2 2 3 1
0 4
1 2
2 2
2 3
3 5

Sample Output

2
0
0
0
1

HINT

对于100%的数据,1<=n,c,m<=10^5


分块嘛
然后思路很显然
根那个BZOJ2724 蒲公英 【分块】其实差不多,然后我也不知道为什么常数老是卡不过去,最后想尽各种办法卡了过去

首先我们可以处理出一个区间内每一种的个数和区间内的众数,可以O(nsqrt(n))时间内预处理出来

然后对于询问暴力枚举两边的不完整块就行了


#include<bits/stdc++.h>
using namespace std;
int read(){
    int ans=0,w=1;char c=getchar();
    while(!isdigit(c)&&c!='-')c=getchar();
    if(c=='-')c=getchar(),w=-1;
    while(isdigit(c))ans=(ans<<1)+(ans<<3)+c-'0',c=getchar();
    return ans*w;
}
#define N 100001
#define M 321
int n,c,m,siz,block_sum,lastans=0;
int a[N],block[N],t[N],L[M],R[M];
int cnt[N][M],ans[M][M];
void init(){
    siz=sqrt(n);
    block_sum=(n-1)/siz+1;
    for(int i=1;i<=n;i++)block[i]=(i-1)/siz+1;
    for(int i=1;i<=block_sum;++i){
        L[i]=R[i-1]+1;
        R[i]=i*siz;
    }R[block_sum]=n;
    for(int i=1;i<=n;++i)++cnt[a[i]][block[i]];
    for(int i=1;i<=c;++i)
        for(int j=1;j<=block_sum;++j)
            cnt[i][j]+=cnt[i][j-1];
    for(int i=1;i<=block_sum;++i){
        int res=0;
        for(int j=i;j<=block_sum;++j){
            for(int k=L[j];k<=R[j];++k)
                if(++t[a[k]]>=2)res+=(t[a[k]]&1)?-1:1;
            ans[i][j]=res;
        }
        for(int j=L[i];j<=n;++j)t[a[j]]--;
    }
}
inline int solve(int l,int r){
    if(block[r]-block[l]<2){
        int res=0;
        for(int i=l;i<=r;++i)
            if(++t[a[i]]>=2)res+=(t[a[i]]&1)?-1:1;
        for(int i=l;i<=r;++i)t[a[i]]--;
        return res;
    }
    //排除边界情况
    int pl=block[l]+(l!=L[block[l]]),ll=L[pl]-1;
    int pr=block[r]-(r!=R[block[r]]),rr=R[pr]+1;
    int res=ans[pl][pr];
    for(int i=l;i<=ll;++i){
        int tmp=cnt[a[i]][pr]-cnt[a[i]][pl-1];
        t[a[i]]+=tmp;
        if(++t[a[i]]>=2)res+=(t[a[i]]&1)?-1:1;
        t[a[i]]-=tmp;
    }
    for(int i=rr;i<=r;++i){
        int tmp=cnt[a[i]][pr]-cnt[a[i]][pl-1];
        t[a[i]]+=tmp;
        if(++t[a[i]]>=2)res+=(t[a[i]]&1)?-1:1;
        t[a[i]]-=tmp;
    }
    for(int i=l;i<=ll;++i)t[a[i]]--;
    for(int i=rr;i<=r;++i)t[a[i]]--;
    return res;
}
int main(){
    n=read();c=read();m=read();
    for(int i=1;i<=n;++i)a[i]=read();
    init();
    for(int i=1;i<=m;++i){
        int l=read(),r=read();
        l=(l+lastans)%n+1;
        r=(r+lastans)%n+1;
        if(l>r)swap(l,r);
        printf("%d\n",lastans=solve(l,r));
    }
    return 0;
}
posted @ 2018-06-23 08:54  Dream_maker_yk  阅读(134)  评论(0编辑  收藏  举报