• [Violet]蒲公英


    查看原题戳这里

    这是一道经典的分块题——用分块求区间众数。分块在线的时间复杂度为O( q sqrt(n) ),离线为O( n sqrt(n) )。

    分块可以进行区间操作,像求区间最值,区间和,区间修改等等。适用范围:分块>线段树>树状数组。

    用分块进行区间操作时,中间的完整的块可以通过预处理来完成,然后两头的就暴力for一下。

    下面是AC代码:

    #include<bits/stdc++.h>
    #define M 50500
    #define mc 500
    #define R register int
    using namespace std;
    struct Violet{int num,x,w;}a[M];
    //num 表示输入顺序
    //x 表示离散化之后的数
    //w 表示原数 
    int block,n,m,answer,tot;
    int s[M],sum[mc][M],ans[mc][mc],belong[M],color[M];
    //s[i] 是离散化之后的数与原数的映射
    //sum[i][j] 是离散化后每个数在每一块中的前缀和
    //ans[i][j] 表示第i-j块的众数
    //belong[i] 第i个数所在的块数
    //color[i] 表示离散化之后数i出现的次数 
    void first();
    void getsum(); 
    void getans();
    void sovle();
    void query(int,int);
    bool cmp1(Violet,Violet);
    bool cmp2(Violet,Violet);
    int main(){
        ios::sync_with_stdio(0);
        first();
        getsum();
        getans();
        sovle();
        return 0;
    }
    void first(){
        cin>>n>>m;
        block=sqrt(n);
        for(R i=1;i<=n;++i) cin>>a[i].w,a[i].num=i;
        sort(a+1,a+n+1,cmp1);
        for(R i=1;i<=n;++i){
            if(a[i].w!=a[i-1].w){
                s[++tot]=a[i].w;
                a[i].x=tot;
            }
            else a[i].x=a[i-1].x;
        }
        sort(a+1,a+n+1,cmp2);
    }
    void getsum(){
        for(R i=1;i<=n;++i){
            belong[i]=i/block;
            ++sum[belong[i]][a[i].x];
        }
        for(R i=0;i<=belong[n];++i)
          for(R j=1;j<=tot;++j)
            sum[i][j]+=sum[i-1][j];
    }
    void getans(){
        for(R i=0;i<=belong[n];++i){
            int be=i*block,now=0;
            if(!be) be=1;
            for(R j=be;j<=n;++j){
                if((++color[a[j].x] > color[now]) || (color[a[j].x] == color[now] && a[j].x<now)) now=a[j].x;
                ans[i][belong[j]]=now;
            }
            for(R j=be;j<=n;++j) --color[a[j].x];
        }
    }
    void sovle(){
        int l,r;
        for(R i=1;i<=m;++i){
            cin>>l>>r;
            l=(l+s[answer]-1)%n+1,r=(r+s[answer]-1)%n+1;
            if(l>r) query(r,l);
            else query(l,r);
        }
    }
    void query(int x,int y){
        int l=x/block+1,r=y/block-1;
        if(r-l<=1){
            answer=0;
            for(R i=x;i<=y;++i)
              if((++color[a[i].x] > color[answer]) || (color[a[i].x] == color[answer] && a[i].x < answer)) answer=a[i].x;
            for(R i=x;i<=y;++i) --color[a[i].x];
            printf("%d
    ",s[answer]);
            return;
        }
        else{
            answer=ans[l][r];
            for(R i=x;i<=l*block-1;++i)
              if(++color[a[i].x]+sum[r][a[i].x]-sum[l-1][a[i].x] > color[answer]+sum[r][answer]-sum[l-1][answer]) answer=a[i].x;
              else if(color[a[i].x]+sum[r][a[i].x]-sum[l-1][a[i].x] == color[answer]+sum[r][answer]-sum[l-1][answer] && a[i].x < answer) answer=a[i].x;
            for(R i=(r+1)*block;i<=y;++i)
              if(++color[a[i].x]+sum[r][a[i].x]-sum[l-1][a[i].x] > color[answer]+sum[r][answer]-sum[l-1][answer]) answer=a[i].x;
              else if(color[a[i].x]+sum[r][a[i].x]-sum[l-1][a[i].x] == color[answer]+sum[r][answer]-sum[l-1][answer] && a[i].x < answer) answer=a[i].x;
            for(R i=x;i<=l*block-1;++i) --color[a[i].x];
            for(R i=(r+1)*block;i<=y;++i) --color[a[i].x];
            printf("%d
    ",s[answer]);
            return;
        }
    }
    bool cmp1(Violet x,Violet y){return x.w<y.w;}
    bool cmp2(Violet x,Violet y){return x.num<y.num;}
  • 相关阅读:
    AcWing 243. 一个简单的整数问题2 (树状数组)打卡
    AcWing 241. 楼兰图腾 (树状数组)打卡
    AcWing 233. 换教室 (期望DP+floyd)打卡
    AcWing 234. 放弃测试 (01分数规划)打卡
    AcWing 232. 守卫者的挑战 (期望DP)打卡
    AcWing 231. 天码 (容斥)打卡
    AcWing 230. 排列计数 水题(组合数+错排)打卡
    AcWing 229. 新NIM游戏 (线性基+博弈论)打卡
    AcWing 228. 异或 (dfs+线性基)打卡
    pstStream->pstPack[i].pu8Addr详解
  • 原文地址:https://www.cnblogs.com/Glacier-elk/p/9767979.html
Copyright © 2020-2023  润新知