zoukankan      html  css  js  c++  java
  • [Violet]蒲公英

    题意:

    给出一个长度为 (n) 序列(a)(m)次询问,每次询问区间 (l,r) 里的众数(出现次数最多的数)。若有多个,输出最小的

    (a_i leq 10^9, n leq 40000, m leq 50000),强制在线。

    题解:

    看了题解才懂的。根据https://www.cnblogs.com/acfunction/p/10051345.html

    hzwer给出了更巧妙的方法http://hzwer.com/3582.html

    (a_i le 10^9),所以先离散化。

    分块大法好!!!

    分析一下:

    求出现次数最多的数,那就预处理一下次数,(s[i][j])表示离散化后(i)个块中(j)出现了多少次

    方法:类似前缀和

    然后为了提高效率,再预处理p数组,(p[i][j])表示离散化后(i)个块到第(j)个块(最小的)众数

    方法:枚举(i,j),开个桶,记录每个数出现的次数,然后去出现次数最多的(数值最小的)。

    接下来:分类讨论

    1. (pr)((r)所在的块)-(pl)((l)所在的块)$geq 2 $

      暴力枚举,和处理(p)数组时差不多。

    2. (pr-pl>2)

      枚举块外,块内的已经预处理好了。

      (每个数的出现次数=块内的(已预处理)+块外的(暴力))

    总的效率为$ O(2n sqrt n + m sqrt n) $

    要注意细节比较多,QwQ。

    代码有点啰嗦,长了点

    #include<bits/stdc++.h>
    #define Fur(i,x,y) for(int i=x;i<=y;i++)
    #define clr(x,y) memset(x,y,sizeof(x))
    int MIN(int x,int y){return x<=y?x:y;}
    void SWAP(int &x,int &y){x^=y;y^=x;x^=y;}
    using namespace std;
    #define N 40040
    int n,m,L,len,s[220][N],val[N],b[N];
    bool vis[N];
    struct nod{int id,val,s;}a[N];
    struct node{int val,s;}p[220][220];
    bool cmp1(nod x,nod y){return x.val<y.val;}
    bool cmp2(nod x,nod y){return x.id<y.id;}
    void pre(){
        Fur(i,1,len){
            clr(b,0);
            node tmp;tmp.val=tmp.s=0;
            Fur(j,i,len){
                Fur(k,(j-1)*L+1,MIN(j*L,n)){
                    b[a[k].s]++;
                    if(b[a[k].s]>tmp.s)tmp.val=a[k].s,tmp.s=b[a[k].s];
                    else if(b[a[k].s]==tmp.s)tmp.val=MIN(tmp.val,a[k].s);
                }
                p[i][j]=tmp;
            }
        }
        Fur(i,1,len){
            Fur(j,1,n)s[i][a[j].s]=s[i-1][a[j].s];
            Fur(j,(i-1)*L+1,MIN(n,i*L))s[i][a[j].s]++;
        }
    }
    int main(){
        ios::sync_with_stdio(false);
        cin>>n>>m;L=sqrt(n);len=(n+L-1)/L;
        Fur(i,1,n)cin>>a[i].val,a[i].id=i;
        sort(a+1,a+n+1,cmp1);a[0].val=-1;
        Fur(i,1,n){
            a[i].s=a[i-1].s+(a[i-1].val!=a[i].val);
            val[a[i].s]=a[i].val;
        }
        sort(a+1,a+n+1,cmp2);
        pre();
        int l,r,la=0,ans=0;
        Fur(i,1,m){
            cin>>l>>r;
            l=(l+la-1)%n+1;r=(r+la-1)%n+1;
            if(l>r)SWAP(l,r);
            int pl=(l-1)/L+1,pr=(r-1)/L+1;
            if(pr-pl<=2){
                ans=0;
                Fur(j,l,r)b[a[j].s]=0;
                Fur(j,l,r){
                    b[a[j].s]++;
                    if(b[a[j].s]>b[ans])ans=a[j].s;
                    else if(b[a[j].s]==b[ans])ans=MIN(ans,a[j].s);
                }
            }
            else{
                ans=p[pl+1][pr-1].val;
                b[ans]=vis[ans]=0;
                Fur(j,l,MIN(n,pl*L))b[a[j].s]=vis[a[j].s]=0;
                Fur(j,(pr-1)*L+1,r)b[a[j].s]=vis[a[j].s]=0;
                Fur(j,l,MIN(n,pl*L))b[a[j].s]++;
                Fur(j,(pr-1)*L+1,r)b[a[j].s]++;
                int mx=0,mxv;
                Fur(j,l,MIN(n,pl*L))if(!vis[a[j].s]){
                    vis[a[j].s]=1;
                    int tmp=b[a[j].s]+s[pr-1][a[j].s]-s[pl][a[j].s];
                    if(mx<tmp)mx=tmp,mxv=a[j].s;
                    else if(mx==tmp)mxv=MIN(mxv,a[j].s);
                }
                Fur(j,(pr-1)*L+1,r)if(!vis[a[j].s]){
                    vis[a[j].s]=1;
                    int tmp=b[a[j].s]+s[pr-1][a[j].s]-s[pl][a[j].s];
                    if(mx<tmp)mx=tmp,mxv=a[j].s;
                    else if(mx==tmp)mxv=MIN(mxv,a[j].s);
                }
                if(mx>b[ans]+p[pl+1][pr-1].s)ans=mxv;
                else if(mx==b[ans]+p[pl+1][pr-1].s)ans=MIN(ans,mxv);
            }
            cout<<(la=val[ans])<<"
    ";
        }
    }
    
  • 相关阅读:
    (数论选拔)联盟阵容
    ai变成bi(递增)最小次数
    状压dp
    dp被3整除的子序列
    离散化+莫队
    dp+哈希
    set的应用
    NOIP 2016 明明的随机数
    洛谷背景更改
    zzulioj 1734 堆
  • 原文地址:https://www.cnblogs.com/mimiorz/p/10321774.html
Copyright © 2011-2022 走看看