zoukankan      html  css  js  c++  java
  • BZOJ4241 : 历史研究

    莫队算法,考虑如何快速维护最大的重要度。

    考虑到答案一共只有$O(n)$种本质不同的取值,于是可以先通过$O(nlog n)$的排序处理出这些值的大小关系,并将这些值离散化,同时对每种事件的每个出现次数维护两个指针pre和nxt,分别表示出现次数减少或增加一后是第几小。

    然后对这些取值进行分块,每块维护该块内有哪些值出现过。

    显然,修改是$O(1)$的。

    查询的时候从后往前扫描,遇到第一个有数字的块就在该块内从后往前扫描,时间复杂度$O(sqrt{n})$。

    于是总的复杂度为$O((n+q)sqrt{n})$。

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=210000,K=9,BUF=6000000,OUT=2000000;
    struct query{int l,r,id;}ask[N];
    int n,q,m,lim,i,pos[N],a[N],b[N],c[N],ap[N];
    int pre[N],nxt[N],loc[N],cnt,sum[N],en[N];ll ans[N];
    struct P{ll x;int y;P(){}P(ll _x,int _y){x=_x,y=_y;}}v[N];
    inline bool cmpv(const P&a,const P&b){return a.x<b.x;}
    inline bool cmp(const query&a,const query&b){return pos[a.l]<pos[b.l]||pos[a.l]==pos[b.l]&&a.r<b.r;}
    inline int lower(int x){
      int l=1,r=n,mid,t;
      while(l<=r)if(b[mid=(l+r)>>1]<=x)l=(t=mid)+1;else r=mid-1;
      return t;
    }
    inline void add(int x){
      int&y=loc[x];
      y=nxt[y],ap[y]=1,sum[y>>K]++;
    }
    inline void del(int x){
      int&y=loc[x];
      ap[y]=0,sum[y>>K]--,y=pre[y];
    }
    inline ll askmax(){
      for(int i=cnt;~i;i--)if(sum[i])for(int j=en[i];j;j--)if(ap[j])return v[j].x;
    }
    char Buf[BUF],*buf=Buf,Out[OUT],*ou=Out;int Outn[30],Outcnt;
    inline void read(int&a){for(a=0;*buf<48;buf++);while(*buf>47)a=a*10+*buf++-48;}
    inline void write(ll x){
      if(!x)*ou++=48;
      else{
        for(Outcnt=0;x;x/=10)Outn[++Outcnt]=x%10+48;
        while(Outcnt)*ou++=Outn[Outcnt--];
      }
    }
    int main(){
      fread(Buf,1,BUF,stdin);read(n);read(q);
      lim=(int)sqrt(n+0.5);
      for(i=1;i<=n;i++)read(a[i]),b[i]=a[i],pos[i]=i/lim;
      sort(b+1,b+n+1);
      for(i=1;i<=n;i++)c[i]=lower(a[i]);
      for(i=1;i<=n;i++)v[++m]=P(0,i);
      for(i=1;i<=n;i++)ap[c[i]]++,v[++m]=P((ll)a[i]*ap[c[i]],c[i]);
      sort(v+1,v+m+1,cmpv);
      for(i=1;i<=n;i++)ap[i]=0;
      for(i=1;i<=m;i++){
        if(ap[v[i].y])pre[i]=ap[v[i].y],nxt[ap[v[i].y]]=i;else loc[v[i].y]=i;
        ap[v[i].y]=en[i>>K]=i;
      }
      cnt=m>>K;
      for(i=1;i<=q;i++)read(ask[i].l),read(ask[i].r),ask[i].id=i;
      sort(ask+1,ask+q+1,cmp);
      for(i=1;i<=n;i++)ap[i]=1,sum[i>>K]++;
      int*l=c+1,*r=c;
      for(i=1;i<=q;i++){
        int*L=c+ask[i].l,*R=c+ask[i].r;
        if(r<R){for(r++;r<=R;r++)add(*r);r--;}
        if(r>R)for(;r>R;r--)del(*r);
        if(l<L)for(;l<L;l++)del(*l);
        else if(l>L){for(l--;l>=L;l--)add(*l);l++;}
        ans[ask[i].id]=askmax();
      }
      for(i=1;i<=q;i++)write(ans[i]),*ou++=10;
      fwrite(Out,1,ou-Out,stdout);
      return 0;
    }
    

      

  • 相关阅读:
    html让表格边框样式为细线
    详解OpenGL中各种绘制集合图形函数
    php利用empty函数判断mysql表单是否为空
    详解OpenGL中各种绘制集合图形函数实现代码:
    约瑟夫环C语言实现源代码
    Delphi 2005 以上版本GIF动画播放设置
    INNO SETUP注册DLL文件
    DELPHI 判断文件夹是否存在,并创建
    BusinessSkinForm汉化文件“bsconst.pas”
    DELPHI2010安装Comport4
  • 原文地址:https://www.cnblogs.com/clrs97/p/4738181.html
Copyright © 2011-2022 走看看