zoukankan      html  css  js  c++  java
  • [BZOJ 2821] 作诗

    Link:

    BZOJ 2821 传送门

    Solution:

    一道类似区间众数的经典分块

    由于个数为偶数这样的条件不能支持快速合并

    因此要先$O(n*sqrt(n))$预处理出$pre[i][j]$表示第$i$块到第$j$块的答案

    同时要建立每种颜色的有序序列方便求出一个区间内某种颜色的个数

    这样每次查询时就能$O(1)$得出整块答案,$O(size*logn)$算出非整块的数对答案的影响

    Code:

    #include <bits/stdc++.h>
    
    using namespace std;
    #define X first
    #define Y second
    #define pb push_back
    typedef double db;
    typedef long long ll;
    typedef pair<int,int> P;
    const int MAXN=1e5+10,CNT=1505;
    vector<int> col[MAXN];
    int n,c,m,l,r,dat[MAXN],pre[CNT][CNT],block;
    int L[MAXN],R[MAXN],sub[MAXN],vis[MAXN],sum[MAXN],cnt,res;
    
    void PRE()
    {
        for(int i=1;i<=cnt;i++)
        {
            int cur=0;
            for(int j=L[i];j<=n;j++)
                sum[dat[j]]=0;
            for(int j=L[i];j<=n;j++)
            {
                if(!(sum[dat[j]]&1)&&sum[dat[j]]) cur--;
                sum[dat[j]]++;
                if(!(sum[dat[j]]&1)) cur++;
                pre[i][sub[j]]=cur;
            }
        }
        for(int i=1;i<=n;i++)
            col[dat[i]].pb(i);
        for(int i=1;i<=c;i++)
            if(col[i].size()) sort(col[i].begin(),col[i].end());
    }
    
    int cal(int x,int l,int r)
    {
        int lft=lower_bound(col[x].begin(),col[x].end(),l)-col[x].begin();
        int rgt=upper_bound(col[x].begin(),col[x].end(),r)-col[x].begin()-1;
        return max(rgt-lft+1,0);
    }
    void work(int pos,int &ret,int l,int r,int x,int y)
    {
        if(vis[dat[pos]]) return;
        int t1=cal(dat[pos],l,r),t2=cal(dat[pos],x,y);
        //注意这里的判断 
        if(!(t1&1)&&(!t2||t2&1)) ret++;
        else if((t1&1)&&!(t2&1)&&t2)ret--;
        vis[dat[pos]]=1;
    }
    int solve(int l,int r)
    {
        int bl=sub[l],br=sub[r],ret=0;
        if(bl==br||bl+1==br)
        {
            for(int i=l;i<=r;i++)
            {
                if(vis[dat[i]]) continue;
                int t=cal(dat[i],l,r);
                ret+=(!(t&1));vis[dat[i]]=1;
            }
            for(int i=l;i<=r;i++) vis[dat[i]]=0;
        }
        else
        {
            ret=pre[bl+1][br-1];
            for(int i=l;i<L[bl+1];i++)
                work(i,ret,l,r,L[bl+1],R[br-1]);
            for(int i=R[br-1]+1;i<=r;i++)
                work(i,ret,l,r,L[bl+1],R[br-1]);    
            for(int i=l;i<L[bl+1];i++) vis[dat[i]]=0;
            for(int i=R[br-1]+1;i<=r;i++) vis[dat[i]]=0;
        }
        return ret;
    }
    
    int main()
    {
        scanf("%d%d%d",&n,&c,&m);
        block=sqrt((double)n/log((double)n)*log(2));
        cnt=n/block+(n%block!=0);
        for(int i=1;i<=n;i++) scanf("%d",&dat[i]);
        for(int i=1;i<=n;i++) sub[i]=(i-1)/block+1;
        for(int i=1;i<=cnt;i++)
            L[i]=(i-1)*block+1,R[i]=i*block;
        R[cnt]=n;PRE();
        
        while(m--)
        {
            scanf("%d%d",&l,&r);
            l=(l+res)%n+1;r=(r+res)%n+1;
            if(l>r) swap(l,r);
            printf("%d
    ",res=solve(l,r));
        }
        return 0;
    }
  • 相关阅读:
    提高 github.com 项目下载速度
    理解git 中的HEAD指针&branch指针
    Docker Compose 配置文件详解
    Yarn 配置阿里源
    Laravel
    reCAPTCHA打不开的解决方法
    CC2 条理分明-----独立思考
    CC2 条理分明-----AACTP教你谈恋爱
    CC4 表达方式----输赢
    lambda匿名函数透析
  • 原文地址:https://www.cnblogs.com/newera/p/9717523.html
Copyright © 2011-2022 走看看