RMQ问题 ST 算法总结 poj3264

sparse table algorithm 简称ST算法,可以用于求解RMQ问题(range minimum query)
ST算法是一个在线算法,在线算法即对于每一个查询可以马上给出解答。但需要较长的时间来进行预处理。
在O(nlogn)的时间内进行预处理,而可以在O(1)的时间内解答每个询问。
预处理:
ST算法预处理利用的是dp的思想。
定义状态dp[i][j] 表示的是从第i个数起2^j个数中最小的数。
举一个例子:
2 9 1 4 5 3 4 5 6这个序列
dp[0][0] 为2 dp[0][1] = 2 dp[0][2] = 1
初始化这个dp数组,dp[i][0] = a[i] ( 0<i<n )
状态的转移:
可以发现dp[i][j]代表的数字一定是一个偶数(j = 0 除外),考虑将2^j的长度分成两份,长度都为2^(j-1)。
两端分别为 i ~ i + 2^(j-1)-1 , i + 2^(j-1) ~ i + 2^j - 1
沿着这思路转移方程:
dp[i][j] = min(dp[i][j-1],dp[i + 2^(j-1)][j-1]) ( 0<= , 2^j < n ,1 <= i < n - 2^j + 1)
查询:
RMQ(i,j) 查询 i ~ j 之间
区间长度len = j - i + 1。求出 2^k <= len < 2^(k+1)
k = log(len) / log(2) ( log 在c语言中同时以e为底)
RMQ(i,j) = min(dp[i][k] , dp[j - 2^k + 1][k])
(这里第二个参数要用dp[j - 2^k + 1][k] 不能用dp[i + 2^k - 1][k] ,因为后者可能是没有定义的)
例如
1 7 3 4 2 5
查询RMQ(0,4) len = 5,k = 2;
dp[0][2] = 1, dp[j - 2^k + 1][2] = dp[1][2] = 2 ,而dp[i + 2^k - 1][k] = dp[0 + 4 - 1][2] 这是没有定义的,因为 3 + 2^2 -1 = 6 >= n,这个在状态转移的时候是不会被更新的,因为这个数组本身没有这么长,这一段在中间的时候就已经到达数组结尾了。

poj 3264

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define M 50009
int a[M];
int mm[M][100];
int mi[M][100];
int n,q;
int main()
{
    //freopen("in.txt","r",stdin);
    while(scanf("%d %d",&n,&q) == 2)
    {
        for(int i = 0;i < n;i++) scanf("%d",&a[i]);
        for(int i = 0;i < n;i++)
        {
            mm[i][0] = a[i];
            mi[i][0] = a[i];
        }
        for(int j = 1;(1<<j) <= n;j++)
        {
            for(int i = 0;i + (1<<j) - 1 < n;i++)
            {
                int m = i + (1<<(j-1));
                mm[i][j] = max(mm[i][j-1],mm[m][j-1]); // i ~ i + 2^(j-1)-1 , i + 2^(j-1) ~ i + 2^j - 1
                mi[i][j] = min(mi[i][j-1],mi[m][j-1]);
            }
        }
        while(q--)
        {
            int a,b;
            scanf("%d %d",&a,&b);
            a--;
            b--;
            int len = b - a + 1;
            int m = (int)(log((double)len) / log(2.0));
            int maxx = max(mm[a][m],mm[b-(1<<m)+1][m]);
            int minn = min(mi[a][m],mi[b-(1<<m)+1][m]);
            printf("%d\n",maxx - minn);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值