LUOGU P4168 [Violet]蒲公英

传送门

解题思路

分块码农题,设分成T块,cnt[i][j][k]表示第i块到第j块,k出现的次数,需要离散化。all[i][j] 表示第i块到第j块的众数。然后这两个数组先预处理出来。然后询问的时候先将答案设成区间大块的众数,然后剩余部分暴力往cnt里加来更新答案。T取n^(1/3)时最优,时间复杂度O(n^(5/3))

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>

using namespace std;
const int MAXN = 40005;
const int MAXSIZ = 40;

inline int rd(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();}
    while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return f?x:-x;
}

int n,m,a[MAXN],cnt[MAXSIZ][MAXSIZ][MAXN],now,all[MAXSIZ][MAXSIZ];
int sum[MAXSIZ][MAXSIZ];
int bl[MAXN],l[MAXSIZ],r[MAXSIZ],siz,num,cpy[MAXN],rk[MAXN];

inline int query(int x,int y){
//  cout<<bl[x]<<" "<<bl[y]<<endl;
    int ret=0,mx=0;
    if(bl[x]==bl[y]){
        for(register int i=x;i<=y;i++){
            int k=rk[i];
            cnt[0][0][k]++;
            if(cnt[0][0][k]>mx) {mx=cnt[0][0][k];ret=a[i];}
            else if(cnt[0][0][k]==mx && a[i]<ret) ret=a[i];
        }
        for(register int i=x;i<=y;i++){
            int k=rk[i];
            cnt[0][0][k]--;
        }
        return ret;
    }ret=all[bl[x]+1][bl[y]-1];mx=sum[bl[x]+1][bl[y]-1];
//  cout<<ret<<" "<<mx<<endl;
//  cout<<r[bl[x]]<<" "<<l[bl[y]]<<endl;
    for(register int i=x;i<=r[bl[x]];i++){
        int k=rk[i];
        cnt[bl[x]+1][bl[y]-1][k]++;
        if(cnt[bl[x]+1][bl[y]-1][k]>mx) ret=a[i],mx=cnt[bl[x]+1][bl[y]-1][k];
        else if(cnt[bl[x]+1][bl[y]-1][k]==mx && a[i]<ret) ret=a[i];
    }
    for(register int i=l[bl[y]];i<=y;i++){
        int k=rk[i];
        cnt[bl[x]+1][bl[y]-1][k]++;
        if(cnt[bl[x]+1][bl[y]-1][k]>mx) ret=a[i],mx=cnt[bl[x]+1][bl[y]-1][k];
        else if(cnt[bl[x]+1][bl[y]-1][k]==mx && a[i]<ret) ret=a[i];
    }
    for(register int i=x;i<=r[bl[x]];i++){
        int k=rk[i];
        cnt[bl[x]+1][bl[y]-1][k]--;
    }
    for(register int i=l[bl[y]];i<=y;i++){
        int k=rk[i];
        cnt[bl[x]+1][bl[y]-1][k]--;
    }
    return ret;
}

int main(){
//  freopen("data.txt","r",stdin);
//  freopen("A.txt","w",stdout);
    n=rd(),m=rd();
    for(register int i=1;i<=MAXSIZ;i++) 
        if(i*i*i>=n) {num=i;break;}
    siz=n/num;num++;
    for(register int i=1;i<=n;i++) bl[i]=(i-1)/siz+1;
    for(register int i=1;i<=num;i++) l[i]=(i-1)*siz+1,r[i]=i*siz;r[num]=n;
    for(register int i=1;i<=n;i++) a[i]=rd(),cpy[i]=a[i];sort(cpy+1,cpy+1+n);
    now=unique(cpy+1,cpy+1+n)-cpy-1;
    for(register int i=1;i<=n;i++) rk[i]=lower_bound(cpy+1,cpy+1+now,a[i])-cpy;
    for(register int i=1;i<=num;i++)
        for(register int j=i;j<=num;j++)
            for(register int k=l[i];k<=r[j];k++){
                int p=rk[k];
                cnt[i][j][p]++;if(cnt[i][j][p]>sum[i][j] 
                or (cnt[i][j][p]==sum[i][j] && a[k]<all[i][j]))
                sum[i][j]=cnt[i][j][p],all[i][j]=a[k];
            }
    int pre=0,x,y;
    while(m--){
        x=rd(),y=rd();x=(x+pre-1)%n+1;y=(y+pre-1)%n+1;
        if(x>y) swap(x,y);pre=query(x,y);
//      cout<<x<<" "<<y<<endl;
        printf("%d
",pre);
    }
    return 0;
} 

原文地址:https://www.cnblogs.com/sdfzsyq/p/9676838.html