ST算法:

   ID数组下标: 1   2   3   4   5   6   7   8   9
      ID数组元素: 5   7   3   1   4   8   2   9   8

1ST算法作用:

  主要应用于求区间最值上,可以把所需要求的区间极大的压缩,并且查询的复杂度为O(1)。比如我们要求一段区间上的最大值,就算是用DP的思想去做,用DP[i][j]表示从i到j区间的最大值,如果需要保存数据元素N比较多的时候,比如N=10000的时候,你开个二维数组肯定超内存,如果你用线段树做的,或许能行得通,不过如果N在更大的时候N=100000,估计线段树每次查询的复杂度为O(log n),询问比较多的时候也容易卡掉。这时候ST算法就派上用场啦~

2、ST算法的主要保存形式是F[i][k]:

  表示的是从n点为起点,长度为2^k的区间最值等价于ID[i][i+2^k-1]的区间大小,当k越大的时候,所代表的区间也越大。需要注意的一点是,区间长度都是2^k去表示的!!!

3、F[i][k]的预处理:

  同样在区间最值求解上,用动态规划的思想去求的每一区间F[i][k]的最值。
  当k=0的时候,区间则表示的变成一个点,也就是i位置上的值。所以DP的初始值也就是F[i][0]=ID[i]。
  然后,动态规划最重要的就算状态转移方程了,以最大值为例子,也就是

F[i][j]=max(F[i][j-1],F[i+2^(j-1)][j-1]);

  说下这个状态转移方程的由来,我们每次求的是F[i][j],也就是ID[]数组所表示的区间[i,i+2^j-1]:

F[i][j]=>ID[i~i+2^j-1]: 

[i.........................................................................................................................i+2^j-1]

  把这个区间二等分,也就是[i,i+2^j-1]=[i,i+2^(j-1)-1]+[i+2^(j-1),i+2^j-1],也就是F[i][j]是由F[i][j-1]和F[i+2^(j-1)][j-1]组成的,这很容易理解,也就是说,每次从二分的子区间中取最值赋值给当前的区间。从而把所有的区间的最值就这样保存下来、

二等分=>[i,i+2^j-1]=[i,i+2^(j-1)-1]+[i+2^(j-1),i+2^j-1]=>F[i][j-1]和F[i+2^(j-1)][j-1]

[i.........................................................................................................................i+2^j-1]

||

[i............................................i+2^(j-1)-1][i+2^(j-1) .....................................i+2^j-1]

4、求解区间[a,b]的最值

  然而,我们需要求的是区间[a,b],并不是这样[i,2^k],这样的区间,求这个F[i][k]表示区间有什么用呢?当然是有用的啦。我们把区间[a,b]转换一下,不就可以了吗、
  我们可以知道区间[a,b]的区间长度为b-a+1,如果你想把区间长度转换成两个2^k,然后求解两个区间的最值,你就想错了,那是不可能的,除非你能够证明任意数N=2^k+2^k,k存在整数解,然后这很明显是错误的,比如N=11就无整数解了的。ST算法的查询只有O(1),他是通过求解区间长度最大的2^k的值,也就是找出一个k,使得2^k<=b-a+1,然后通过比较区间[a,a+2^k-1]和[b-2^k+1,b]取最值实现的,这里的a+2^k-1并不一定会等于b-2^k+1,而且一般情况下都是大于的情况、
        [a...................................................................b]
        [a....................... (a+2^k-1)]
                    [(b-2^k+1)....................b]
求解这两个区间的最值也就是求解区间[a,b]最值了的。
首先我们要先求出K,计算方法就是:
           2^k=b-a+1 
           =>k=log2(b-a+1) 

        =>k=lg(b-a+1) /lg(2)

        =>k=(int)(log(b-a+1.0)/log(2.0));

(PS:C中的lg的计算是用log表示Orz,Orz,Orz........)

5,一些证明:

  求解出的k表示的是长度b-a+1表示成2的N次方,最大能够表示的N,一定会使得:2^k<=b-a+1.

证明:2^k>=(b-a+1)/2。        

  假设求的的k是最大的次方,如果2^k小于区间长度(b-a+1)的一半,

  则说明区间(b-a+1)的长度大于2个2^k,2^k+2^k=2^(k+1),

  也就是说这段区间(b-a+1)中还存在n=k+1使得2^n > 2^k,与假设不符,

  所以,2^k>=(b-a+1)/2恒成立、

代码:(2015.8.14)

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <math.h>
 4 #define max(a,b) (a)>(b)?(a):(b)
 5 #define min(a,b) (a)<(b)?(a):(b)
 6 #define MAX 100010
 7 using namespace std;
 8 int maxsum[MAX][20];
 9 int minsum[MAX][20];
10 int Num[MAX];
11 void Cread_ST(int N) //预处理->O(nlogn)
12 {
13     for(int i=1;i<=N;i++)maxsum[i][0]=minsum[i][0]=Num[i];
14     int Len=(int)(log(N)/log(2.0));
15     for(int j = 1; j <=Len; j++){
16         for(int i = 1;i+(1<<j)-1<= N; i++){
17             int TMD=i+(1<<(j-1));
18             maxsum[i][j]=max(maxsum[i][j-1],maxsum[TMD][j-1]);
19             minsum[i][j]=min(minsum[i][j-1],minsum[TMD][j-1]);
20         }
21     }
22 }
23 int RMQ(int l,int r)
24 {
25     int k,TMD,Max,Min;
26     k=(int)(log(r-l+1.0)/log(2.0));
27     TMD=r-(1<<k)+1;
28     Max=max(maxsum[l][k],maxsum[TMD][k]);
29     Min=min(minsum[l][k],minsum[TMD][k]);
30     return Max-Min;
31 }
32 int main()
33 {
34     int N,i,Q,a,b,k,Max,Min;
35     while( scanf("%d%d",&N,&Q)!=EOF)
36     {
37         for(i=1;i<=N;i++)
38             scanf("%d",&Num[i]);
39         Cread_ST(N);
40         while(Q--)
41         {
42             scanf("%d %d",&a,&b);
43             printf("%d\n",RMQ(a,b));
44         }
45     }
46     return 0;
47 }

View Code

**************************************
* 作者: Wurq
* 博客: http://www.cppblog.com/wurq/
* 日期: 2017/8/16
**************************************

转载于:https://www.cnblogs.com/Wurq/p/4730614.html

【原创】RMQ - ST算法详解相关推荐

  1. 【原创】KMP算法详解

    前言 KMP算法是学习数据结构 中的一大难点,不是说它有多难,而是它这个东西真的很难理解(反正我是这么感觉的,这两天我一直在研究KMP算法,总算感觉比较理解了这套算法, 在这里我将自己的思路分享给大家 ...

  2. Apollo6.0代码Lattice算法详解——Part4:计算障碍物ST/SL图

    Apollo6.0代码Lattice算法详解--Part4:计算障碍物ST/SL图 0.前置知识 1.涉及主要函数 2.函数关系 3.部分函数代码详解 3.1 lattice_planner.cc中代 ...

  3. YOLOv5算法详解

    目录 1.需求解读 2.YOLOv5算法简介 3.YOLOv5算法详解 3.1 YOLOv5网络架构 3.2 YOLOv5实现细节详解 3.2.1 YOLOv5基础组件 3.2.2 输入端细节详解 3 ...

  4. CenterNet算法详解

    Objects as Points-论文链接-代码链接 目录 1.需求解读 2.CenterNet算法简介 3.CenterNet算法详解 3.1 CenterNet网络结构 3.2 CenterNe ...

  5. SoftPool算法详解

    Refining activation downsampling with SoftPool-论文链接-代码链接 目录 1.需求解读 2.SoftPool算法简介 3.SoftPool算法详解 3.1 ...

  6. Popular Cows POJ - 2186(tarjan算法)+详解

    题意: 每一头牛的愿望就是变成一头最受欢迎的牛.现在有 N头牛,给你M对整数(A,B),表示牛 A认为牛B受欢迎.这种关系是具有传递性的,如果 A认为 B受欢迎, B认为 C受欢迎,那么牛 A也认为牛 ...

  7. Unicode双向算法详解(bidi算法)(二)

    作者:黄邦勇帅(原名:黄勇)2019-10-17 Unicode双向算法详解(bidi算法)(二) 本文为原创文章,转载请注明出处,或注明转载自"黄邦勇帅(原名:黄勇) 本文是对<C+ ...

  8. Unicode双向算法详解(bidi算法)(一)

    Unicode双向算法详解(bidi算法)(一) 注:本文已独家授权给脚本之家(ID:jb51net)公众号发布 本文为原创文章,转载请注明出处,或注明转载自"黄邦勇帅(原名:黄勇) 本文是 ...

  9. Unicode双向算法详解(bidi算法)(三)

    Unicode双向算法详解(bidi算法)(三) 本文为原创文章,转载请注明出处,或注明转载自"黄邦勇帅(原名:黄勇) 本文是对<C++语法详解>一书相关章节的增补,以增强读者对 ...

最新文章

  1. Zend Studio 10正式版破解(2013-02-26更新)
  2. 【ObjectC—浅copy和深copy】
  3. 字符设备驱动基本流程
  4. 为什么我的elec352稍微有点崩
  5. java 设计作业——学生类的基本练习
  6. java redis set list_RedisTemplate的各种操作(set、hash、list、string)_lichuangcsdn的博客-CSDN博客...
  7. apache目录遍历漏洞利用_Apache漏洞—多后缀名解析、目录遍历和(CVE-2017-15715)
  8. 如何用计算机装手机系统,如何用手机usb重装电脑系统
  9. 18 计量单位xx未对语言xx定义/在语言xx中没有维护短文本
  10. Ubuntu16.04下配置pip国内镜像源加速安装
  11. Windows系统好用的文本编辑器
  12. 该内存不能为written或read的解决方案(比较全)
  13. 3.2 基本数据类型
  14. 培养架构思维成为优秀的架构师
  15. Tableau可视化技巧-让你的图表跟随时间动起来
  16. 计算机原理说课教案,《计算机系统及工作原理说课稿》
  17. img图片在webpack中使用
  18. 软件构造|GRASP模式
  19. nginx+lua实现限流降级(使用lua的lua-resty-limit-traffic)
  20. Unity VR:如何获得手柄的按键信息

热门文章

  1. FAIR 何恺明、Piotr、Ross等新作,MAE才是YYDS!仅用ImageNet1K,Top-1准确率87.8%!
  2. 项目落地才是硬道理!TensorFlow 2 牛了
  3. 近期 AI 领域,招聘招生信息汇总
  4. 谷歌官方推出 TensorFlow 中文视频:机器学习从零到一(系列之二)
  5. 李航老师亲自推荐的《统计学习方法》课件下载
  6. 吓人!普京最新Deepfake视频来了,MIT现场伪造实时采访
  7. 送10本今年最火的《动手学深度学习》
  8. python字符串结合操作符的使用
  9. C语言?看女程序员是怎么往死里坑师兄的
  10. 2018年度计算机视觉GtiHub top开源项目!