详解RMQ-ST算法 ST模板
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模板相关推荐
- Apollo6.0代码Lattice算法详解——Part4:计算障碍物ST/SL图
Apollo6.0代码Lattice算法详解--Part4:计算障碍物ST/SL图 0.前置知识 1.涉及主要函数 2.函数关系 3.部分函数代码详解 3.1 lattice_planner.cc中代 ...
- 最形象的卷积神经网络详解:从算法思想到编程实现(转载)
mark一下,感谢作者分享! 原标题:最形象的卷积神经网络详解:从算法思想到编程实现 1 新智元推荐 查看全文 http://www.taodudu.cc/news/show-4611564.html ...
- 【算法知识】详解希尔排序算法
前言 已发布: [算法知识]详解选择冒泡算法 [算法知识]详解选择排序算法 [算法知识]详解插入排序算法 当待插入元素是一个很小(当需求是从小到大排序时,从大到小排序时此处为很大)直接插入排序需要移动 ...
- 【算法知识】详解直接插入排序算法
前言 已发布: [算法知识]详解选择冒泡算法 [算法知识]详解选择排序算法 在玩扑克牌的时候,我们抽到一张牌的时候,都是将它插入到当前手中牌的合适位置的. 如下图: (上图来自算法导论) 直接插入排序 ...
- 算法详解_常用算法详解——打印杨辉三角形
杨辉三角,是二项式系数在三角形中的一种几何排列.在中国南宋数学家杨辉1261年所著的<详解九章算法>一书中出现.在欧洲,这个表叫做帕斯卡三角形.帕斯卡(1623----1662)是在165 ...
- es6字符串添加html标签,JavaScript_详解JavaScript ES6中的模板字符串,在 ES6 中引入了一种新的字符 - phpStudy...
详解JavaScript ES6中的模板字符串 在 ES6 中引入了一种新的字符串字面量 - 模板字符串,除了使用反引号 (`) 表示,它们看上去和普通的字符串没有什么区别.在最简单的情况下,他们就是 ...
- js模板字符串自定义类名_详解JavaScript ES6中的模板字符串
这篇文章主要介绍了详解JavaScript ES6中的模板字符串,JS的ES6版本带来诸多简洁化方面的重大改进,需要的朋友可以参考下 在 ES6 中引入了一种新的字符串字面量 - 模板字符串,除了使用 ...
- DDA画线算法+代码详解-直线扫描算法之一
#DDA画线算法+代码详解-直线扫描算法之一 本文目录结构如下 1.直线扫描算法简介 2.DDA直线扫描算法 2.1 公式推理 1.求斜率K: 2.当|K| <= 1 时 3.当|K| > ...
- 小白给小白详解维特比算法(一)
小白给小白详解维特比算法(一) 小白给小白详解维特比算法一 篱笆网络Lattice的最短路径问题 这个问题长什么样子 这个问题难在哪里 简化成这个模样你总能回答了吧 下一步我们该干什么 别倒立了我们再 ...
- 算法经典“钓鱼”问题详解 基于贪心算法 C语言描述
算法经典"钓鱼"问题详解 基于贪心算法 初始条件 在一条水平路边,有 n 2 ≤ n ≤ 25个钓鱼池,从左到右编号为1.2.3.--.n.小明有H1 ≤ H ≤ 16个小时的空余 ...
最新文章
- 鱼佬:我的数据挖掘之路!
- Visual C++ 2011-6-6
- Wannafly挑战赛21 E 未来城市规划
- GraphPad Prism 教程 :标准差与平均值的标准误差有什么区别
- 简单使用CXF实现webserver(rs的独立发布)
- 通知:即日起本博客暂停更新,请移步至yanxin8.com获取最新文章
- bzoj1034题解
- 微软Skype即将抛弃Windows Phone 8和8.1用户
- 没搞懂bios设置这5个问题,千万别重装系统!
- ubuntu 旺旺_Ubuntu 下通过Wine安装阿里旺旺并解决中文乱码
- 新概念下兴起域名商机 云域名是神马浮云
- Excel合并单元格中间插入斜杠和数字保留一位小数
- Xbox 360抢鲜测评
- unity启动Logo大小的问题
- keras yolo3 使用 CIOU Loss
- 算法的时间复杂度和空间复杂度总结
- 蜗牛—cocos2dx之初识
- DHCP和交换机的工作原理
- 织梦网站定时审核,定时发布织梦插件
- windows下python利用f2py调用Fortran