[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\n",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\n",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;}

 

posted @ 2018-10-10 17:43  Glacier-elk  阅读(282)  评论(0编辑  收藏  举报