RMQ算法(st表)

支持操作:询问区间[L,R]的最小值。
预处理操作复杂度O(nlog n),查询复杂度O(1) 。

预处理:令d(i,j)表示从i开始长度为2j的最小值,则有
d(i,j)=min( d(i,j-1) , d(i+2j-1,j-1) )

原理:
把长度为2j分成一半,则一半为 i ~ 2j-1-1,另一半为i+2j-1 ~ 2j

预处理代码:

void RMQ_init(const vector<int>& A)
{
    int n=A.size();
    for(int i=0;i<n;i++) d[i][0]=A[i];
    for(int j=1;(1<<j)<=n;j++)
        for(int i=0;i+(1<<j)-1<n;i++)
        d[i][j]=min(d[i][j-1],d[i+(1<<(j-1))][j-1]);
}

查询操作:令k为满足2k<=R-L+1的最大整数,则以L开头,R结尾的两个长度为2k的区间和起来即覆盖了查询区间[L,R]。
(解析:第一个区间为L到L+2k,另一个区间设起点为x,则R-x+1=2k,解得x=R-2k+1,所以另一个区间为R-2k+1到R)。
有些元素重复考虑了几遍也没关系,因为是取最小值。如果是求和,则不允许出现重复考虑的元素。

查询代码:

int RMQ(int L,int R)
{
    int k=0;
    while((1<<(k+1))<=R-L+1) k++; //2^(k+1)<=R-L+1,那么k还可以加1
    return min(d[L][k],d[R-(1<<k)+1][k]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值