RMQ

RMQ是一种离线算法,通常用于求出区间【l,r】中的最大值或者最小值。

 

显然这种问题用线段树是能解决的,我之前也一直用的线段树完成这题。

 

 

RMQ,简称ST算法。 通过进行(nlogn)的预处理等操作,使询问的时间复杂度  达到  O(1),在此当然也蕴含着dp的思想。

 

 

具体:

  设立一个数组dp【i】【j】  存着区间【i , i + 2^j-1】的最大值或者最小值,显然【i , i + 2^j-1】可以写成【i , i + 1<<j -1】

  同时区间【i , i + 2^j-1】  可以看成  【i,i+2^(j-1)-1】和  【i +2^(j-1), i + 2^j-1】的组成。       即转移方程:【i , i + 2^j-1】=max(【i,i+2^(j-1)-1】 ,【i +2^(j-1), i + 2^j-1】 )

    简化后dp【i】【j】=max(dp【i】【j-1】,dp【i+(1<<(j-1))】【j-1】)

 

预处理:

 

void init()
{
    for (int i=1;i<=n;i++){
        cin>>dpmax[i][0];
        dpmin[i][0]=dpmax[i][0];
    }
    for (int j=1;(1<<j)<=n;j++){
        for (int i=1;(i+(1<<j)-1)-1<=n;i++){
            dpmax[i][j]=max(dpmax[i][j-1],dpmax[i+(1<<(j-1))][j-1]);
            dpmin[i][j]=min(dpmin[i][j-1],dpmin[i+(1<<(j-1))][j-1]);
        }
    }
    return ;
}

 

询问:

  通常给出,左边界 l 和 右边界 r 的确切值,求区间【l,r】的最大值或最小值

 

此时我们只需要得到满足       2^k<=( r-l+1 )     的k的最大值

 

然后把区间分为两个可以相交的区间,分别为【l , l+2^k-1】和 【r-2^k+1 , r 】      

     简化下就是:  dp【l】【k】 和 dp【r-(1<<k)+1】【k】

int query(int l,int r)
{
    int k=0,len=r-l+1;
    while ((1<<(k+1))<=len){
        k++;
    }
    return max(dpmax[l][k],dpmax[r-(1<<k)+1][k])-min(dpmin[l][k],dpmin[r-(1<<k)+1][k]);
}

 

练习题:  poj   3264  

  1.借鉴博客    求区间最值问题

  2.借鉴博客    求lca问题   (对于一棵树,求两个节点的最近公共祖先)

 

 

 

 

posted @ 2019-07-18 14:44  生活待我如初恋  阅读(351)  评论(0编辑  收藏  举报