rmq

转移自老blog

rmq倍增

struct RMQ{
    static const int maxn=1000,lgmaxn=12;
    static int lg[maxn];
    int mx[maxn][lgmaxn];

    RMQ(){//构造函数
        if(lg[2]!=1){
            for(int i=2;i<maxn;i++){ //因为lg(1)=0
                lg[i]=(i&-i)==i?lg[i-1]+1:lg[i-1];
            }
        }
    }

    void build(int n,int *a){
        for(int i=0;i<=n;i++)mx[i][0]=a[i];
        for(int j=1;j<=lg[n+1];j++)
            for(int i=0;i+(1<<j)-1<=n;i++)
                mx[i][j]=max(mx[i][j-1],mx[i+(1<<(j-1))][j-1]);
    }

    int query(int l,int r){
        int k=lg[r-l+1];
        return max(mx[l][k],mx[r-(1<<k)+1][k]);
    }
};
inline int max(int a,int b,int c,int d){return max(max(a,b),max(c,d));}
struct RMQ2{//写的时候下标从0开始,可以当作下标为1开始来使用
    static const int maxn=310,lgmaxn=9;//确保 ( 1<<(lgmaxn-1) ) > maxn
    static int lg[maxn];//log2(x)向下取整
    int mx[maxn][maxn][lgmaxn][lgmaxn];
    RMQ2(){//构造函数不用管的
        if(lg[2]!=1){
            for(int i=2;i<maxn;i++){ //因为lg(1)=0
                lg[i]=(i&-i)==i?lg[i-1]+1:lg[i-1];
            }
        }
    }
    void build(int row,int col,int a[][maxn]){//[0,row],[0,col]
        for(int i=0;i<=row;i++)for(int j=0;j<=col;j++)mx[i][j][0][0]=a[i][j];

        for(int ii=0; (1<<ii)<=row+1; ii++){
            for(int jj=0; (1<<jj)<=col+1; jj++){
                for(int i=0; i+(1<<ii)-1<=row; i++){
                    for(int j=0; j+(1<<jj)-1<=col; j++){
                        if     (ii!=0)mx[i][j][ii][jj]=max(mx[i][j][ii-1][jj],mx[i+(1<<(ii-1))][j][ii-1][jj]);
                        else if(jj!=0)mx[i][j][ii][jj]=max(mx[i][j][ii][jj-1],mx[i][j+(1<<(jj-1))][ii][jj-1]);
                    }
                }
            }
        }
    }
    int query(int r1,int c1,int r2,int c2){
        if(r1>r2)swap(r1,r2);
        if(c1>c2)swap(c1,c2);
        int kr=lg[r2-r1+1], r3=r2+1-(1<<kr);
        int kc=lg[c2-c1+1], c3=c2+1-(1<<kc);
        return max(mx[r1][c1][kr][kc],mx[r1][c3][kr][kc],
                   mx[r3][c3][kr][kc],mx[r3][c1][kr][kc]);
    }
};int RMQ2::lg[maxn];
/******************    on预处理 O1在线查询rmq   *****************/
double Ospace(double n,double blk){
    return pow(2,blk)+2*n/blk+blk+5*n+2*n/blk*ceil(log(2*n/blk)/log(2))+2*n/blk;
}
const int maxn=2e7+21,blk=20,lgmxn=22;//  2^b+2n/b+b    +   2n+2n+n+2n/b*lg+2n/b) = 2^b+5n+b+2n/b(2+lg)
int pre[1<<blk],lg[(maxn<<1)/blk],hi[blk];
void prework(){
    hi[0]=0; for(int i=1;i<blk;i++) hi[i]=hi[i-1]>>1|(1<<(blk-1));
    lg[1]=0; for(int i=2;i*blk<(maxn<<1);i++) lg[i]=lg[i>>1]+1;
    vector<int>sum(1<<blk);// 节约空间
    int b=(1<<blk)-1;
    for(int i=0;i<(1<<blk);i++){
        sum[i^b]=i&1?-1:1;pre[i^b]=0;
        if(sum[i>>1^b]<0) sum[i^b]+=sum[i>>1^b],pre[i^b]=pre[i>>1^b]+1;
    }
}
struct o1rmq{
    int dep[maxn<<1],p[maxn<<1],fst[maxn];
    int rmq[(maxn<<1)/blk][lgmxn],bin[(maxn<<1)/blk];
    int *ls=rmq[0],*rs=ls+maxn;// 内存复用

    void upd(int&x,int y){if(dep[x]>dep[y]) x=y;}
    void build(int n,int*dat){// [0,n)
        int *s=fst,top=0,step=-1;// 内存复用,  使用单调栈为dat建立笛卡尔树
        for(int i=0;i<n;i++){
            ls[i]=rs[i]=-1;
            while(top>0&&dat[i]<dat[s[top]]) ls[i]=s[top--];  // < is min and > is max
            if(top>0)rs[s[top]]=i;
            s[++top]=i;
        }
        dfs(s[1],1,step);//对笛卡尔树进行ett分解,此后ls,rs,栈s将无用处,可以丢弃。

        int exn=(2*n-1+blk-1)/blk;//对ett分块  拓展到blk的倍数
        for(int i=2*n-1;i<exn*blk;i++)dep[i]=dep[i-1]+1;
        for(int i=0;i<exn;i++){
            bin[i]=0;
            for(int j=0;j<blk;j++) if(j==0||dep[i*blk+j]>dep[i*blk+j-1]) bin[i]|=1<<j;
            rmq[i][0]=i*blk+pre[bin[i]];
        }
        for(int j=1;0+(1<<j)<=exn;j++){// 对块进行rmq
            for(int i=0;i+(1<<j)<=exn;i++){//[i,i+1<<j)
                rmq[i][j]=rmq[i][j-1]; upd(rmq[i][j],rmq[i+(1<<(j-1))][j-1]);
            }
        }
    }
    void dfs(int u,int d,int&step){
        p[++step]=u;
        dep[step]=d;
        fst[u]=step;
        if(ls[u]!=-1){
            dfs(ls[u],d+1,step);
            p[++step]=u;
            dep[step]=d;
        }
        if(rs[u]!=-1){
            dfs(rs[u],d+1,step);
            p[++step]=u;
            dep[step]=d;
        }
    }
    int query(int l,int r){//[l,r]  query max value, return idx of min value
        l=fst[l],r=fst[r]; if(l>r)swap(l,r);
        int l1=l/blk,l2=l%blk,r1=r/blk,r2=r%blk;
        if(l1==r1) return p[l+pre[bin[l1]>>l2|hi[blk-(r2-l2+1)]]];
        else{
            int bl=l1*blk==l?l1:l1+1,br=r1*blk+blk-1==r?r1:r1-1;
            int ret=l;
            if(bl<=br) {
                int k=lg[br-bl+1];
                upd(ret,rmq[bl][k]);
                upd(ret,rmq[br-(1<<k)+1][k]);
            }
            if(l1!=bl) upd(ret,l+pre[bin[l1]>>l2|hi[blk-(blk-1-l2+1)]]);
            if(r1!=br) upd(ret,((br+1)*blk)+pre[bin[r1]|hi[blk-(r2-0+1)]]);
            return p[ret];
        }
    }
}rmq;
分块rmq
/******************  O(7n)-O(3) rmq  *****************/
int ospace(int n,int base){return (n>>base)+(n>>base)*ceil(log(n>>base)/log(2))+n*(base+1);}
const int base=5,blk=1<<base,maxn=2e7+7+blk,lgnb=21;
int lg[maxn>>base];
void prework(){
    lg[1]=0; for(int i=2;i*blk<maxn;i++) lg[i]=lg[i>>1]+1;
}
struct normalrmq{
    int rmq[blk][base+1];
    void build(int n,int*a){//[0,n)
        for(int i=0;i<n;i++)rmq[i][0]=a[i];
        for(int j=1;0+(1<<j)-1<n;j++)
            for(int i=0;i+(1<<j)-1<n;i++)
                rmq[i][j]=max(rmq[i][j-1],rmq[i+(1<<(j-1))][j-1]);
    }
    int query(int l,int r){
        int k=lg[r-l+1];
        return max(rmq[l][k],rmq[r-(1<<k)+1][k]);
    }
};
struct O7nO3rmq{
    int rmq[maxn/blk][lgnb];
    normalrmq rmq2[maxn/blk];
    void build(int n,int*a){//
        int exn=(n+blk-1)/blk;
        for(int i=0;i<exn;i++){
            rmq2[i].build(blk,a+i*blk);
            rmq[i][0]=rmq2[i].query(0,blk-1);
        }
        for(int j=1;0+(1<<j)-1<exn;j++)
            for(int i=0;i+(1<<j)-1<exn;i++)
                rmq[i][j]=max(rmq[i][j-1],rmq[i+(1<<(j-1))][j-1]);
    }
    int query(int l,int r){
        int l1=l/blk,l2=l%blk,r1=r/blk,r2=r%blk;
        if(l1==r1) return rmq2[l1].query(l2,r2);
        else {
            int bl=l1*blk==l?l1:l1+1,br=r1*blk+blk-1==r?r1:r1-1;
            int ret=1<<31;
            if(bl<=br) {
                int k=lg[br-bl+1];
                ret=max(rmq[bl][k],rmq[br-(1<<k)+1][k]);
            }
            if(l1!=bl) ret=max(ret,rmq2[l1].query(l2,blk-1));
            if(r1!=br) ret=max(ret,rmq2[r1].query(0,r2));
            return ret;
        }
    }
}rmq;