【bzoj2821】作诗(Poetize)

分块做法*

ps:第一篇博客,有点小激动,有错误大佬别怼我;

题目大概是这样的;
类似于区间众数,在询问的区间中统计出现过偶数次的元素和。
那么这种类型的题目分块比暴力优越在哪??是的,只是因为预处理而已;

先用f[i][j]统计出:第i块 到 第j块中询问的答案;

对于不完整的块,我们最多做不超过块大小两倍,时间上有保证;

查询*

对于区间[a,b],可分为三个部分:1.[a,min(b,bl[a]*blo], 2.[bl[a]*blo+1,(bl[b-1]*blo], 3.[bl[b-1]*blo+1,b];

注意到第二部分的答案是已知的,那么影响结果的只能是1,3部分的元素;

每个暴力查询他在大区间中出现的次数,判断他在完整的块里是否被统计过,修改rtn;

应该就这些,另外对于查询他出现的次数,二分就行了,用vector记录这个元素所有出现的位置,看哪些在[a,b]中;

好了,代码如xia:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <algorithm>
#include <map>
#define LL long long
using namespace std;

int read(){
    int rtn=0,f=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch<='9'&&ch>='0')rtn=rtn*10+ch-'0',ch=getchar();
    return rtn*f;
}

int n,q,c,id,lastans,m,v[100010],blo,flag[100010],cnt[100010],bl[100010],f[1505][1505];
vector<int>ve[100010];//不用vector写法复杂一些,蒟蒻不会; 
//如果按照sqrt(n/log(n)*log(2))分,块的数量比原来增多,; 
void reset(int x){
    int l=(x-1)*blo+1,tot=0;
    for(int i=l;i<=n;i++)cnt[v[i]]=0;
    for(int i=l;i<=n;i++){
        int t=bl[i];
        cnt[v[i]]++;
        if(cnt[v[i]]==1){
            f[x][t]=tot;
            continue;
        }
        if(!(cnt[v[i]]&1))tot++;
        if(cnt[v[i]]&1)tot--;
        f[x][t]=tot;
        //预处理,偶数加一,奇数减一,等于一的时候特判; 
    }
}

int Query(int l,int r,int x){
    return (upper_bound(ve[x].begin(),ve[x].end(),r)-
            lower_bound(ve[x].begin(),ve[x].end(),l));
}

int query(int a,int b){
    int ans=0,l=bl[a]*blo+1,r=(bl[b]-1)*blo;
    if(bl[a]==bl[b]||bl[a]+1==bl[b]){
        for(int i=a;i<=b;i++){
            if(flag[v[i]])continue;
            int t1=Query(a,b,v[i]);
            if(!(t1&1)){flag[v[i]]=1;ans++;}
        }
        for(int i=a;i<=b;i++)flag[v[i]]=0;
    }
    else{
        ans=f[bl[a]+1][bl[b]-1];
        for(int i=a;i<=bl[a]*blo;i++){
            if(flag[v[i]])continue;
            int t1=Query(a,b,v[i]);
            int t2=Query(l,r,v[i]);
            if(!(t1&1))
                if(t2&1||!t2)ans++;
            if(t1&1)
                if(!(t2&1)&&t2)ans--;
            flag[v[i]]=1; 
        }
        for(int i=(bl[b]-1)*blo+1;i<=b;i++){
            if(flag[v[i]])continue;
            int t1=Query(a,b,v[i]);
            int t2=Query(l,r,v[i]);
            if(!(t1&1))
                if(t2&1||!t2)ans++;
            if(t1&1)
                if(!(t2&1)&&t2)ans--;
            flag[v[i]]=1;
        } 
        for(int i=a;i<=bl[a]*blo;i++)flag[v[i]]=0;
        for(int i=(bl[b]-1)*blo+1;i<=b;i++)flag[v[i]]=0; 
    }
    return ans;

}

int main()
{
    n=read(),c=read(),q=read();
    blo=sqrt((double)n/log((double)n)*log(2));//注意块大小 
    for(int i=1;i<=n;i++){
        v[i]=read();
        bl[i]=(i-1)/blo+1;
        ve[v[i]].push_back(i);
    }
    if(n%blo)m=n/blo+1;
    else m=n/blo;
    for(int i=1;i<=m;i++)reset(i);
    for(int i=1;i<=q;i++){
        int x=read(),y=read();
        x=(x+lastans)%n+1,y=(y+lastans)%n+1;
        if(x>y)swap(x,y);
        lastans=query(x,y);
        printf("%d
",lastans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/DexterYsw/p/7136256.html