RMQ问题是求解区间最值的问题。

这里分析的是ST算法,它可以对所有要处理的数据做到O(nlogn)的预处理,对每个区间查询做到O(1)查询

ST算法本质是一个DP的过程

这里通过举一个求最大值实例来理解ST算法:

我们有这样一串数字

数值:35 13 65 99 88 75 64 51 42  55 66 83 12 44 65 12

位置:1    2  3   4   5   6   7    8   9  10 11 12 13 14 15 16

首先我们定义一个dp表达式:st[i][j]表示从i位置开始的2^j个数中的最大值;

具体解释:st[1][0]就是从第一个数字开始的一个数里的最大值,也就是第一个数本身,即st[1][0]=35;

             st[2][2]就是从第二个数字开始的四个数里的最大值,也就是13,65,99,88里面的最大值,即st[2][2]=99;

     以此类推

  然后我们来看怎么用dp的思想来解决这个问题

  回到刚刚的实例,我们由我们所定义的st式可以得知st[5][3]是[88,75,64,51,42,55,66,83]中的最大值。

  现在我们来试着用dp的思想,也就是将整体化为部分求解的思想。

  要求前面st[5][3]所代表区间的最大值,也就是求[88,75,64,51]和[42,55,66,83]两个区间的最大值中的较大值,即st[5][2]和st[9][2]

而这样的划分是一个二分划分,根据这种思想我们可以类推出,求i至其后2^j个数的最大值,即把2^j分成前后两个2^(j-1),分别取最大值,再通过比较获得此状态最大值。

到此我们可以得出我们的dp表达式:st[i][j] = max( st[i][j-1],st[i+2^(j-1)][j-1] )

通过这种方法我们可以求出一段段区间的最大值

求ST表代码

void cal_st( int n, int a[] ) {  //n为区间元素个数,a数组存的是区间里的元素for( int i = 1; i <= n; i ++ ) {st[i][0] = a[i];}for( int j = 1; j <= log2(n); j ++ ) {for( int i = 1; i <= n-(1<<j)+1; i ++ ) {st[i][j] = max(st[i][j-1],st[i+(1<<(j-1))][j-1]);}}
}

  

  

接下来让我们回到RMQ问题:

  我们可以知道,任意的i至j之间的j-i+1个连续的值,一定可以分为两个2^n个数的两个区间

  比如求3到11之间的最大值;

  因为3到11之间有9个元素,最大可以成8个元素大小的区间;

  所以我们可以将其分为[3,10]和[4,11]两个区间;(分成的两个区间一个是从开头取八个,一个是从最后往前取八个)

  然后通过求这两个区间最大值中的较大值得到3到11之间的最大值

抽象成一个广义数学问题:

  求[i,j]区间最大值;

  num = j-i+1; p = 2^((int)(log2(num)));

  rmq(i,j) = max( st[i][p], st[i-2^p+1][p] )

  num:[i,j]区间元素个数,p:[i,j]区间可以连续分成的最大2^n区间的大小

  rmq(i,j):查询[i,j]区间最大值

rmq查询代码:

int rmq( int le, int ri ) {  //le为查询区间开始位置,ri为查询区间结束位置int p = log2(ri-le+1);return max(st[le][p],st[ri-(1<<p)+1][p]);
}

  

参考博客:https://blog.csdn.net/z287438743z/article/details/8132806

例题:洛谷P3865

题目背景

这是一道ST表经典题——静态区间最大值

请注意最大数据时限只有0.8s,数据强度不低,请务必保证你的每次查询复杂度为 O(1)

题目描述

给定一个长度为 N 的数列,和 M 次询问,求出每一次询问的区间内数字的最大值。

输入输出格式

输入格式:

第一行包含两个整数 N, M ,分别表示数列的长度和询问的个数。

第二行包含 N个整数(记为 ai​ ),依次表示数列的第 i 项。

接下来 M 行,每行包含两个整数 li​,ri​ ,表示查询的区间为[li​,ri​]

输出格式:

输出包含 M 行,每行一个整数,依次表示每一次询问的结果。

输入输出样例

输入样例

8 8
9 3 1 7 5 6 0 8
1 6
1 5
2 7
2 6
1 8
4 8
3 7
1 8

输出样例

9
9
7
7
9
8
7
9

说明

对于30%的数据,满足:1≤N,M≤10

对于70%的数据,满足: 1≤N,M≤105

对于100%的数据,满足: 1≤N≤105,1≤M≤106,ai​∈[0,10^9],1≤li​≤ri​≤N

分析:一个st表的模板题

  st[i][j]表示以第i个数为首的一共2^j个数的最大值

  ai表示原数列

可以得到:

if( j == 1 ) {st[i][j] = a[i]
} else {st[i][j] = max( st[i][j-1], st[i+(1<<(j-1))][j-1] );
}

  

AC代码:

#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <vector>
#include <string>
#include <bitset>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
#define ls (r<<1)
#define rs (r<<1|1)
#define debug(a) cout << #a << " " << a << endl
using namespace std;
typedef long long ll;
const ll maxn = 1e5+10;
const ll mod = 998244353;
const double pi = acos(-1.0);
const double eps = 1e-8;
ll st[maxn][20];  //ll表示long long,个人习惯整数定义成long long
void cal_st( ll n, ll a[] ) {for( ll i = 1; i <= n; i ++ ) {st[i][0] = a[i];}for( ll j = 1; j <= log2(n); j ++ ) {for( ll i = 1; i <= n-(1<<j)+1; i ++ ) {st[i][j] = max(st[i][j-1],st[i+(1<<(j-1))][j-1]);}}
}ll rmq( ll le, ll ri ) {ll p = log2(ri-le+1);return max(st[le][p],st[ri-(1<<p)+1][p]);
}
int main() {ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);ll n, t, a[maxn];scanf("%lld%lld",&n,&t);for( ll i = 1; i <= n; i ++ ) {scanf("%lld",&a[i]);}cal_st(n,a);while( t -- ) {ll le, ri;scanf("%lld%lld",&le,&ri);printf("%lld\n",rmq(le,ri));}return 0;
}

  

  

转载于:https://www.cnblogs.com/l609929321/p/9439145.html

详解RMQ-ST算法 ST模板相关推荐

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

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

  2. 最形象的卷积神经网络详解:从算法思想到编程实现(转载)

    mark一下,感谢作者分享! 原标题:最形象的卷积神经网络详解:从算法思想到编程实现 1 新智元推荐 查看全文 http://www.taodudu.cc/news/show-4611564.html ...

  3. 【算法知识】详解希尔排序算法

    前言 已发布: [算法知识]详解选择冒泡算法 [算法知识]详解选择排序算法 [算法知识]详解插入排序算法 当待插入元素是一个很小(当需求是从小到大排序时,从大到小排序时此处为很大)直接插入排序需要移动 ...

  4. 【算法知识】详解直接插入排序算法

    前言 已发布: [算法知识]详解选择冒泡算法 [算法知识]详解选择排序算法 在玩扑克牌的时候,我们抽到一张牌的时候,都是将它插入到当前手中牌的合适位置的. 如下图: (上图来自算法导论) 直接插入排序 ...

  5. 算法详解_常用算法详解——打印杨辉三角形

    杨辉三角,是二项式系数在三角形中的一种几何排列.在中国南宋数学家杨辉1261年所著的<详解九章算法>一书中出现.在欧洲,这个表叫做帕斯卡三角形.帕斯卡(1623----1662)是在165 ...

  6. es6字符串添加html标签,JavaScript_详解JavaScript ES6中的模板字符串,在 ES6 中引入了一种新的字符 - phpStudy...

    详解JavaScript ES6中的模板字符串 在 ES6 中引入了一种新的字符串字面量 - 模板字符串,除了使用反引号 (`) 表示,它们看上去和普通的字符串没有什么区别.在最简单的情况下,他们就是 ...

  7. js模板字符串自定义类名_详解JavaScript ES6中的模板字符串

    这篇文章主要介绍了详解JavaScript ES6中的模板字符串,JS的ES6版本带来诸多简洁化方面的重大改进,需要的朋友可以参考下 在 ES6 中引入了一种新的字符串字面量 - 模板字符串,除了使用 ...

  8. DDA画线算法+代码详解-直线扫描算法之一

    #DDA画线算法+代码详解-直线扫描算法之一 本文目录结构如下 1.直线扫描算法简介 2.DDA直线扫描算法 2.1 公式推理 1.求斜率K: 2.当|K| <= 1 时 3.当|K| > ...

  9. 小白给小白详解维特比算法(一)

    小白给小白详解维特比算法(一) 小白给小白详解维特比算法一 篱笆网络Lattice的最短路径问题 这个问题长什么样子 这个问题难在哪里 简化成这个模样你总能回答了吧 下一步我们该干什么 别倒立了我们再 ...

  10. 算法经典“钓鱼”问题详解 基于贪心算法 C语言描述

    算法经典"钓鱼"问题详解 基于贪心算法 初始条件 在一条水平路边,有 n 2 ≤ n ≤ 25个钓鱼池,从左到右编号为1.2.3.--.n.小明有H1 ≤ H ≤ 16个小时的空余 ...

最新文章

  1. 鱼佬:我的数据挖掘之路!
  2. Visual C++ 2011-6-6
  3. Wannafly挑战赛21 E 未来城市规划
  4. GraphPad Prism 教程 :标准差与平均值的标准误差有什么区别
  5. 简单使用CXF实现webserver(rs的独立发布)
  6. 通知:即日起本博客暂停更新,请移步至yanxin8.com获取最新文章
  7. bzoj1034题解
  8. 微软Skype即将抛弃Windows Phone 8和8.1用户
  9. 没搞懂bios设置这5个问题,千万别重装系统!
  10. ubuntu 旺旺_Ubuntu 下通过Wine安装阿里旺旺并解决中文乱码
  11. 新概念下兴起域名商机 云域名是神马浮云
  12. Excel合并单元格中间插入斜杠和数字保留一位小数
  13. Xbox 360抢鲜测评
  14. unity启动Logo大小的问题
  15. keras yolo3 使用 CIOU Loss
  16. 算法的时间复杂度和空间复杂度总结
  17. 蜗牛—cocos2dx之初识
  18. DHCP和交换机的工作原理
  19. 织梦网站定时审核,定时发布织梦插件
  20. windows下python利用f2py调用Fortran

热门文章

  1. 《教父》,没有什么电影是非看不可的
  2. 【运维培训】课程调研PPT部分内容存档
  3. 大数据技术在建筑节能中的应用探究
  4. (翻译)2022 年免费的 4 个最佳文本到语音在线工具
  5. div、p标签超出换行
  6. vue 项目dev/sit/uat环境判断
  7. java属性定义_在java中定义抽象属性
  8. 【李南江】从零玩转TypeScript
  9. asp编程工具_asp.net core 成为构建企业首选
  10. python在财务方面的应用-财务数据分析与Python