欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

BZOJ4241 : 历史研究

程序员文章站 2022-05-27 18:56:19
...

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

考虑到答案一共只有$O(n)$种本质不同的取值,于是可以先通过$O(n\log 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;
}