蒲公英

题意

求一段区间的众数,相同次数选小的那个。强制在线

对于 100% 的数据,保证1n40000,1m50000,1ai109

题解

如果不要求强制在线就可以用回滚莫队解决。

那在线怎么做?还是考虑分块,预处理出第i块到第j块这段区间的桶和众数。

对于一段区间查询[l,r],分成3部分,(l,L)和(R,r)两个不足一整段的部分和中间的整块区间[L,R]。

每次查询就在预处理的[pos[L],pos[R]]基础上统计答案,最后再撤销即可。

算法事件复杂度(NS2+MN/S),空间复杂度(NS2),设N,M为相同数量级,那么S=N1/3时复杂度在(N5/3),S为块的个数

注意离散化

#include<bits/stdc++.h>
using namespace std;

const int maxn=40005;
int n,m;
int a[maxn],b[maxn];
int size,pos[maxn];
int cnt[40][40][maxn],nowans[40][40];//第i块到第j块的各数的个数和众数 
int ans;

template<class T>inline void read(T &x){
    x=0;char ch=getchar();
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
}

void nice(int i,int j,int cx[],int &nowans){//预处理,nowans必须加&,否则不能改变 
    int l=size*(i-1)+1,r=min(n,size*j);
    for(int k=l;k<=r;k++){
      cx[a[k]]++;
      if(cx[nowans]<cx[a[k]]) nowans=a[k];
      else if(cx[nowans]==cx[a[k]]&&a[k]<nowans) nowans=a[k];
    }
}  

int good[maxn];

void sto324(int l,int r){//暴力 
    for(int i=l;i<=r;i++)
     good[a[i]]=0;
    for(int i=l;i<=r;i++){
        good[a[i]]++;
        if(good[a[i]]>good[ans]) ans=a[i];
        else if(good[a[i]]==good[ans]&&a[i]<ans) ans=a[i];
    }
    return ;
}

void get_it(int l,int r){
    ans=0;
    if(pos[r]-pos[l]<=1){sto324(l,r);return ;}//在同一块或相邻块,保证[L,R]成立 
    int L=pos[l]+1,R=pos[r]-1;
    ans=nowans[L][R];
    for(int i=l;pos[i]==pos[l];i++){
        cnt[L][R][a[i]]++;
        if(cnt[L][R][a[i]]>cnt[L][R][ans]) ans=a[i];
        else if(cnt[L][R][a[i]]==cnt[L][R][ans]&&a[i]<ans) ans=a[i];
    }
    for(int i=r;pos[i]==pos[r];i--){
        cnt[L][R][a[i]]++;
        if(cnt[L][R][a[i]]>cnt[L][R][ans]) ans=a[i];
        else if(cnt[L][R][a[i]]==cnt[L][R][ans]&&a[i]<ans) ans=a[i];
    }
    for(int i=l;pos[i]==pos[l];i++) cnt[L][R][a[i]]--;
    for(int i=r;pos[i]==pos[r];i--) cnt[L][R][a[i]]--;//撤销操作 
}

int main(){
    read(n);read(m);
    size=(int)pow(n,2.0/3);
    for(int i=1;i<=n;i++){
        read(a[i]);
        b[i]=a[i];
        pos[i]=(i-1)/size+1;
    }
    sort(b+1,b+n+1);
    int tot=unique(b+1,b+n+1)-b-1;
    for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+tot+1,a[i])-b;
    for(int i=1;i<=pos[n];i++)
     for(int j=i;j<=pos[n];j++)
      nice(i,j,cnt[i][j],nowans[i][j]);
    for(int i=1;i<=m;i++){
        int l,r;
        read(l);read(r);
        l=(l+b[ans]-1)%n+1;
        r=(r+b[ans]-1)%n+1;
        if(l>r) swap(l,r);
        //printf("%d %d
",l,r);
        get_it(l,r);
        printf("%d
",b[ans]);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/sto324/p/11240104.html