P4168 [Violet]蒲公英

P4168 [Violet]蒲公英

分块

吸了氧气才过

强制在线区间众数,具体见hzwer的解题报告(右转Baidu)

先把数字离散化

然后对于每个数字开个动态数组存出现的位置

每次对完整块的众数和不完整块的所有数在动态数组中进行查询,答案必定在它们之中

code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
#include<cctype>
using namespace std;
inline int Int(){
    char c=getchar(); int x=0;
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x;
}
inline int min(int &a,int &b) {return a<b ?a:b;}
int n,m,ans,mxd,cnt,_blo,blo[40002],a[40002],f[210][210],mp[40002],ct[40002];
vector <int> v[40002];
map <int,int> Map;
inline void pre(int x){ //预处理整块的区间众数
    memset(ct,0,sizeof(ct)); int mx=0,t=0;
    for(int i=(x-1)*_blo+1;i<=n;++i){
        ++ct[a[i]];
        if(ct[a[i]]>mx||(mx==ct[a[i]]&&mp[a[i]]<mp[t])) t=a[i],mx=ct[a[i]];
        f[x][blo[i]]=t; //第x块到blo[i]块之间的众数
    }
}
inline int find(int l,int r,int k){ //区间内出现的次数
    return upper_bound(v[k].begin(),v[k].end(),r)-lower_bound(v[k].begin(),v[k].end(),l);
}
inline void query(int l,int r){
    ans=f[blo[l]+1][blo[r]-1];
    mxd=find(l,r,ans); //完整块的众数
    for(int i=min(blo[l]*_blo,r);i>=l;--i){ //对于不完整的块,对所有数暴力查询
        int t=find(l,r,a[i]);
        if(t>mxd||(t==mxd&&mp[a[i]]<mp[ans])) mxd=t,ans=a[i];
    }
    if(blo[l]==blo[r]) return ;
    for(int i=(blo[r]-1)*_blo+1;i<=r;++i){
        int t=find(l,r,a[i]);
        if(t>mxd||(t==mxd&&mp[a[i]]<mp[ans])) mxd=t,ans=a[i];
    }
}
int main(){
    n=Int(); m=Int(); _blo=sqrt(n); int q1,q2;
    for(int i=1;i<=n;++i){
        a[i]=Int();
        if(!Map[a[i]]) Map[a[i]]=++cnt,mp[cnt]=a[i];
        a[i]=Map[a[i]]; //离散化
        v[a[i]].push_back(i);
        blo[i]=(i-1)/_blo+1;
    }
    for(int i=1;i<=blo[n];++i) pre(i);
    for(int i=1;i<=m;++i){
        q1=Int(); q2=Int();
        q1=(q1+ans-1)%n+1,q2=(q2+ans-1)%n+1;
        if(q1>q2) swap(q1,q2);
        query(q1,q2); ans=mp[ans];
        printf("%d\n",ans);
    } return 0;
}

猜你喜欢

转载自www.cnblogs.com/kafuuchino/p/9652989.html