P4168 (静态分块

P4168 (静态分块

题意:区间众数,强制在线

思路:离线考虑莫队,在线考虑静态分块。块之间的贡献不独立, a n s [ i ] [ j ] ans[i][j] ans[i][j]表示块 [ i , j ] [i,j] [i,j]中的众数, m x [ i ] [ j ] mx[i][j] mx[i][j]表示众数的出现次数,通过增量法求解, O ( n 2 / B ) O(n^2/B) O(n2/B)考虑块与块之间的影响,用 c n t [ i ] [ j ] cnt[i][j] cnt[i][j]表示前 i i i个块中 j j j的出现次数

  • 查询

    用散块暴力更新看是否对整块的答案有所贡献即可 $O(B+n/B) $ 块大小为 n \sqrt n n 的时候时空复杂度为 O ( n n ) O(n\sqrt n) O(nn )

    注意这题值域需要离散化

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=40005;
    int cnt[250][maxn],mx[250][250],ans[250][250],tmp[maxn];
    int a[maxn],n,m,big,pos[maxn],num,L[250],R[250],b[maxn],id[maxn],c;
    void init(){
        big=sqrt(n);
        num=(n-1)/big+1;
        for(int i=1;i<=num;++i){
            L[i]=(i-1)*big+1;
            R[i]=i*big;
        }
        R[num]=n;
        for(int i=1;i<=num;++i)
            for(int j=L[i];j<=R[i];++j)pos[j]=i;
        sort(b+1,b+1+n);
        c=unique(b+1,b+1+n)-(b+1);
        for(int i=1;i<=n;++i){
            int x=lower_bound(b+1,b+1+c,a[i])-b;
            id[x]=a[i];
            a[i]=x;
        }
        for(int i=1;i<=n;++i){
            cnt[pos[i]][a[i]]++;
        } 
        for(int i=2;i<=num;++i){
            for(int j=1;j<=c;++j)
                cnt[i][j]+=cnt[i-1][j];
        }
        for(int i=1;i<=num;++i){
            int x=0,z=0;//mx ans
            for(int j=L[i];j<=n;++j){
                tmp[a[j]]++;
                if(tmp[a[j]]>x)x=tmp[a[j]],z=a[j];
                else if(tmp[a[j]]==x&&z!=a[j]){
                    z=min(z,a[j]);
                }
                mx[i][pos[j]]=x;ans[i][pos[j]]=z;
            }
            for(int j=L[i];j<=n;++j)tmp[a[j]]--;
        }
    }
    int query(int l,int r){
        int pl=pos[l],pr=pos[r];
        if(pl==pr){
            int x=0,z=0;
            for(int i=l;i<=r;++i){
                tmp[a[i]]++;
                if(tmp[a[i]]>x)x=tmp[a[i]],z=a[i];
                else if(tmp[a[i]]==x&&z!=a[i]){
                    z=min(z,a[i]);
                }
            }
            for(int i=l;i<=r;++i)tmp[a[i]]--;
            return z;
        }else{
            int x=mx[pl+1][pr-1],z=ans[pl+1][pr-1];
            for(int i=l;i<=R[pl];++i)tmp[a[i]]=cnt[pr-1][a[i]]-cnt[pl][a[i]];
            for(int i=l;i<=R[pl];++i){
                tmp[a[i]]++;
                if(tmp[a[i]]>x)x=tmp[a[i]],z=a[i];
                else if(tmp[a[i]]==x&&a[i]!=z)z=min(z,a[i]);
            }
            for(int i=L[pr];i<=r;++i)
                tmp[a[i]]=tmp[a[i]]?tmp[a[i]]:cnt[pr-1][a[i]]-cnt[pl][a[i]];
            for(int i=L[pr];i<=r;++i){
                tmp[a[i]]++;
                if(tmp[a[i]]>x)x=tmp[a[i]],z=a[i];
                else if(tmp[a[i]]==x&&a[i]!=z)z=min(z,a[i]);
            }
            for(int i=l;i<=R[pl];++i)tmp[a[i]]=0;
            for(int i=L[pr];i<=r;++i)tmp[a[i]]=0;
            return z;
        }
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i)
            scanf("%d",&a[i]),b[i]=a[i];
        init();
        int l,r,anss=0;
        for(int i=1;i<=m;++i){
            scanf("%d%d",&l,&r);
            l=(l+anss-1)%n+1;r=(r+anss-1)%n+1;
            if(l>r)swap(l,r);
            cout<<(anss=id[query(l,r)])<<"\n";
        }
        return 0;
    }
    
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值