bzoj4865: [Ynoi2017]由乃运椰子

Posted ccz181078

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj4865: [Ynoi2017]由乃运椰子相关的知识,希望对你有一定的参考价值。

在线询问区间众数,传统的分块(记录块间众数和每个权值的出现次数)做法被卡空间(分块用的空间是O(块数*(块数+权值种类数))),因此考虑去掉出现次数较小的数,只用分块维护出现次数较大的数。设K为分界线,用原来的分块维护原序列中出现次数>K的数组成的部分,而出现次数<=K的数,可以通过记录一个数前面第1~K个相同的数的位置,用线段树维护,线段树查询时利用单调性单次询问可以做到$O(k+logn)$,不会成为瓶颈。

当K取$O(n^{1/4})$时,时间复杂度仍是$O(q\sqrt{n})$,空间复杂度为$O(n^{5/4})$

#include<bits/stdc++.h>
char buf[65555],*ptr=buf+65536;
int g(){
    if(ptr-buf==65536)fread(buf,1,65536,stdin)[buf]=0,ptr=buf;
    return *ptr++;
}
int __(){
    int x=0,c=g();
    while(c<48)c=g();
    while(c>47)x=x*10+c-48,c=g();
    return x;
}
int _(){
    if(ptr-buf>65500)return __();
    int x=0,c=*ptr++;
    while(c<48)c=*ptr++;
    while(c>47)x=x*10+c-48,c=*ptr++;
    return x;
}
typedef unsigned short u16;
int n,m;
int v0[60007],vs[60007],B,v1[60007],vp1=0;
u16 bc[365][6677],ws[60007],t[60007],rid[60007],bb[365][365],pv[60007],pw[60007];
int ls[405],rs[405];
u16 tr[131111][7];
int max(int a,int b){return a>b?a:b;}
int get(int l,int r){
    int p=0;
    for(int a=l+65535,b=r+65537;b-a!=1&&p<7;a>>=1,b>>=1){
        if(~a&1)while(p<7&&tr[a^1][p]>=l)++p;
        if(b&1)while(p<7&&tr[b^1][p]>=l)++p;
    }
    return p+1;
}
int main(){
    n=_();m=_();
    for(int i=1;i<=n;++i)vs[i]=v0[i]=_();
    std::sort(vs+1,vs+n+1);
    for(int i=1;i<=n;++i)v0[i]=std::lower_bound(vs+1,vs+n+1,v0[i])-vs;
    for(int i=1;i<=n;++i){
        int x=v0[i];
        pv[i]=pw[x];
        pw[x]=i;
        for(int j=0,z=pv[i];j<7;++j)tr[i+65536][j]=z,z=pv[z];
    }
    for(int i=65535;i;--i){
        int a=i<<1,b=a^1;
        for(int j=0;j<7;++j)tr[i][j]=max(tr[a][j],tr[b][j]);
    }
    for(int i=1;i<=n;++i)++t[v0[i]];
    int idp=0;
    for(int i=1;i<=n;++i)if(t[i]>8)rid[i]=++idp;
    
    for(int i=1;i<=n;++i)if(rid[v0[i]]){
        v1[++vp1]=rid[v0[i]];
        v0[i]=vp1;
    }else v0[i]=v0[i-1];
    for(int i=1;i<=n;++i)t[i]=0;
    n=vp1;
    for(B=1;n/B>362;++B);
    for(int l=1,r=B,c=1;l<=n;l+=B,r+=B,++c){
        if(r>n)r=n;
        ls[c]=l;rs[c]=r;
        for(int i=ls[c];i<=rs[c];++i)ws[i]=c;
        for(int b=c;b;--b){
            bb[c][b]=bb[c][b+1];
            for(int i=ls[b];i<=rs[b];++i)if(v1[i]){
                int x=++bc[c][v1[i]];
                if(x>bc[c][bb[c][b]])bb[c][b]=v1[i];
            }
        }
    }
    int la=0;
    while(m--){
        int L=_()^la,R=_()^la;
        int a0=get(L,R);
        L=v0[L-1]+1;R=v0[R];
        int l=ws[L],r=ws[R];
        if(a0<8)la=a0;
        else if(r-l<=1){
            la=a0;
            for(int i=L;i<=R;++i){
                int x=v1[i];
                if(x&&++t[x]>la)la=t[x];
            }
            for(int i=L;i<=R;++i)--t[v1[i]];
        }else{
            --r,++l;
            int mx=bb[r][l];
            u16*s1=bc[r],*s2=bc[l-1];
            for(int i=rs[l-1];i>=L;--i){
                int x=v1[i];
                int t1=++t[x]+s1[x]-s2[x];
                if(t1>t[mx]+s1[mx]-s2[mx])mx=x;
            }
            for(int i=ls[r+1];i<=R;++i){
                int x=v1[i];
                int t1=++t[x]+s1[x]-s2[x];
                if(t1>t[mx]+s1[mx]-s2[mx])mx=x;
            }
            la=max(a0,t[mx]+bc[r][mx]-bc[l-1][mx]);
            for(int i=rs[l-1];i>=L;--i)--t[v1[i]];
            for(int i=ls[r+1];i<=R;++i)--t[v1[i]];
        }
        printf("-%d\n",la);
    }
    return 0;
}

 

以上是关于bzoj4865: [Ynoi2017]由乃运椰子的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ4811[Ynoi2017]由乃的OJ 树链剖分+线段树

[BZOJ]4810: [Ynoi2017]由乃的玉米田

bzoj 4811: [Ynoi2017]由乃的OJ

BZOJ4811 [Ynoi2017]由乃的OJ

BZOJ4810 [Ynoi2017]由乃的玉米田

莫队bzoj4866: [Ynoi2017]由乃的商场之旅