解析


ST 算法是 RMQ(Range Minimum/Maximum Query)中一个很经典的算法,它天生用来求得一个区间的最值,但却不能维护最值,也就是说,过程中不能改变区间中的某个元素的值。O(nlogn) 的预处理和 O(1) 的查询对于需要大量询问的场景是非常适用的。接下来我们就来详细了解下 ST 算法的处理过程。

比如有如下长度为 10 的数组:

1 3 2 4 9 5 6 7 8 0  

我们要查询 [1, 7] 之间的最大值,如果采用朴素的线性查找,复杂度O(n),而 ST 算法却只需要 O(1)的时间复杂度,因为 ST 算法预处理了一个 dp 数组。

我们用 dp[i][j] 表示从 i 开始的 2^j 个数的最值,表示 dp[i][j] “管辖” index=i 开始的 2^j 个数字,那么很显然,任何一段区间都能被两个 dp 元素管辖到。比如上面说的 [1, 7],就能被dp[1][2] 和 dp[4][2]管辖到,而 max(dp[1][2], dp[4][2])也就是[1, 7] 的最值了。

如何得出是 dp[1][2] 和 dp[4][2] 这两个元素?很简单,让dp[1][n](2^n <= 区间个数)中的n尽可能大就得到了第一个元素,从而可以推得第二个元素,两个元素的管辖范围大小是一样的。

这样我们只需预处理一个 dp 数组就可以了,而这个预处理是一个动态规划的过程,转移方程为:

dp[i][j] = max(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);

而 dp 数组的预处理和 RMQ 的求解过程正好是个逆过程。

实战


POJ 上有一道 ST 算法的模板题 Balanced Lineup,只需预处理两个数组即可,一个表示最大值,另一个表示最小值。

完整代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define N 50005
int maxn[N][32], minn[N][32];
int a[N];

void ST(int n) {
  for (int i = 1; i <= n; i++)
    maxn[i][0] = minn[i][0] = a[i];

  int k = log(n * 1.0) / log(2.0);

  for (int j = 1; j <= k; j++)
    for (int i = 1; i <= n; i++) {
    if (i + (1 << j) - 1 > n) break;
      maxn[i][j] = max(maxn[i][j - 1], maxn[i + (1 << (j - 1))][j - 1]);
      minn[i][j] = min(minn[i][j - 1], minn[i + (1 << (j - 1))][j - 1]);
    }
}

int getAns(int x, int y) {
  int k = log(y - x + 1.0) / log(2.0);
  return max(maxn[x][k], maxn[y + 1 - (1 << k)][k]) - min(minn[x][k], minn[y + 1 - (1 << k)][k]);
}

int main() {
  int n, cas;
  scanf("%d%d", &n, &cas);
  for (int i = 1; i <= n; i++)
    scanf("%d", &a[i]);

  ST(n);

  while (cas--) {
    int x, y;
    scanf("%d%d", &x, &y);
    printf("%d\n", getAns(x, y));
  }

  return 0;
}

Javascript模板:

var G = {
  dp: [], // dp[i][j] 表示从 index=i 开始的连续 2^j 个元素中的最值

  init: function(a) {
    var n = a.length;

    for (var i = 0; i < n; i++)
      G.dp[i] = [], G.dp[i][0] = a[i]; 

    var k = ~~(Math.log(n) / Math.log(2));

    for (var j = 1; j <= k; j++)
      for (var i = 0; i < n; i++) {
        if (i + (1 << j) - 1 >= n) break;
        // 如果求区间最小值,改为 Math.min() 即可
        G.dp[i][j] = Math.max(G.dp[i][j - 1], G.dp[i + (1 << (j - 1))][j - 1]);
      }
  },

  getAns: function(x, y) {
    var k = ~~(Math.log(y - x + 1) / Math.log(2));
    // 如果求区间最小值,改为 Math.min() 即可
    return Math.max(G.dp[x][k], G.dp[y + 1 - (1 << k)][k]);
  }
};

var a = [1, 3, 2, 4, 8, 7, 6, 5, 9, 0]  // 需要求 RMQ 的数组

G.init(a);

// test cases
for (var i = 0; i < 10; i++)
  for (var j = i + 1; j < 10; j++) {
    var tmp = a.slice(i, j + 1)
      , normalAns = Math.max.apply(null, tmp)
      , stAns = G.getAns(i, j);

    if (normalAns !== stAns)
      console.log('Algorithm went wrong!');
  }

求解区间最值 - RMQ - ST 算法介绍的更多相关文章

  1. 【原创】RMQ - ST算法详解

    ST算法: ID数组下标: 1   2   3   4   5   6   7   8   9    ID数组元素: 5   7   3   1   4   8   2   9   8 1.ST算法作 ...

  2. HDU 3183 - A Magic Lamp - [RMQ][ST算法]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3183 Problem DescriptionKiki likes traveling. One day ...

  3. 关于基础RMQ——ST算法

    RMQ,Range Maximum/Minimum Query,顾名思义,就是询问某个区间内的最大值或最小值,今天我主要记录的是其求解方法--ST算法 相对于线段树,它的运行速度会快很多,可以做到O( ...

  4. [POJ3264]Balanced Lineup(RMQ, ST算法)

    题目链接:http://poj.org/problem?id=3264 典型RMQ,这道题被我鞭尸了三遍也是醉了…这回用新学的st算法. st算法本身是一个区间dp,利用的性质就是相邻两个区间的最值的 ...

  5. POJ 3264 Balanced Lineup RMQ ST算法

    题意:有n头牛,编号从1到n,每头牛的身高已知.现有q次询问,每次询问给出a,b两个数.要求给出编号在a与b之间牛身高的最大值与最小值之差. 思路:标准的RMQ问题. RMQ问题是求给定区间内的最值问 ...

  6. RMQ st算法 区间最值模板

    #include<bits/stdc++.h> ; ; int f[N][Logn],a[N],lg[N],n,m; int main(){ cin>>n>>m; ...

  7. Balanced Lineup:线段树:区间最值 / RMQ

    不要被线段树这个名字和其长长的代码吓到. D - Balanced Lineup Description For the daily milking, Farmer John's N cows (1 ...

  8. POJ 3368 Frequent values RMQ ST算法/线段树

                                                         Frequent values Time Limit: 2000MS   Memory Lim ...

  9. RMQ(模板 ST 区间最值,频繁的间隔时间)

    PS: 介绍:http://blog.csdn.net/liang5630/article/details/7917702 RMQ算法.是一个高速求区间最值的离线算法,预处理时间复杂度O(n*log( ...

随机推荐

  1. 网络编程4--毕向东java基础教程视频学习笔记

    Day24 06 自定义浏览器-Tomcat服务端07 自定义图形界面浏览器-Tomcat服务端08 URL-URLConnection09 小知识点10 域名解析 06 自定义浏览器-Tomcat服 ...

  2. Java api 入门教程 之 JAVA的Random类

    在实际的项目开发过程中,经常需要产生一些随机数值,例如网站登录中的校验数字等,或者需要以一定的几率实现某种效果,例如游戏程序中的物品掉落等. 在Java API中,在java.util包中专门提供了一 ...

  3. Hadoop环境常用命令

    用户可以通过dfsadmin -safemode value   来操作安全模式,参数value的说明如下: enter - 进入安全模式 leave - 强制NameNode离开安全模式 get - ...

  4. shell 面试题

      1. 用sed修改test.txt的23行test为tset:     sed –i ‘23s/test/tset/g’ test.txt 2. 查看/web.log第25行第三列的内容.     ...

  5. cookie和session详解

    cookie和session的区别 二者的定义: 当你在浏览网站的时候,WEB 服务器会先送一小小资料放在你的计算机上,Cookie 会帮你在网站上所打的文字或是一些选择,都纪录下来.当下次你再光临同 ...

  6. 买错的电影票,含着泪也得看-LAMP搭建&Linux基础

    hi 没说过,上周五室友过生请客,在龙湖里吃嗨了喝爽了,回去的路上侃侃而谈.说好的这周一起去看年内最后的大片,火星救援的,谁知道老子眼神不好,买错了电影的时间...把周六的约定提前到了今儿个下午,ma ...

  7. DPM(voc-release5) Matlab模型文件 Mat转XML

    (转载请注明作者和出处 楼燚(yì)航的blog :http://www.cnblogs.com/louyihang loves baiyan/ 未经允许请勿用于商业用途) 由于目前DPM模型训练的代 ...

  8. NOIP2000方格取数[DP]

    题目描述 设有N*N的方格图(N<=9),我们将其中的某些方格中填入正整数,而其他的方格中则放 人数字0.如下图所示(见样例): A 0 0 0 0 0 0 0 0 0 0 13 0 0 6 0 ...

  9. 计算2的N次方&&计算e

    2的N次方 注意:这里在处理的时候并没有用循环来处理,而是用移位的做法.    n<<4  就是 n*2^4    ,所以在本例中只需要写 1<<time  (time是要求的 ...

  10. 第五章项目:QuickHit

    需求概述: 根据输入速率和正确率将玩家分为不同级别,级别越高,一次显示的字符数越多,玩家正确输入一次的得分也越高.如果玩家在规定时间内完成规定次数的输入,正确率达到规定要求,则玩家升级(为了简单起见, ...