ST表
ST(实质是动态规划) 是一个用来解决rmq(区间最值)问题的算法
ST不支持在线修改, 离线查询
预处理时间复杂度O(nlogn), 查询时间为O(1)。
构建ST表
用mn[i][j]
记录 [i, i+2j-1]的最值(长度为2j)
因此对于任意mn[i][j]
= min(前半段最小值, 后半段最小值)
,即mn[i][j] = min(mn[i][j-1], mn[i+pow(i,j-1)][j-1])
, 如下图:
因此, 以长度为状态, 一层一层的求出每个结果。
由此看来构建复杂度为O(nlogn)
构建代码实现
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+50;// 根据数组长度取值
int arr[maxn];//初始数组
//最小值得ST表
int mn[maxn][25]; //第二维度根据题目来定
// 构建ST表的函数
void init(int sz)
{
//长度为1的状态
for(int i = 1;i <= sz;i++)
mn[i][0] = arr[i];
for(int j = 1;(i << j)<= sz;j++)//循环长度
{
for(int i = 0;i+(1<<j)-1<= sz;i++)//求该长度下的所有状态
mn[i][j] = min(mn[i][j-1], mn[i+(1<<(j-1))][j-1]);
}
}
查询
- 因为, 数学上
2^log(len) == a
(在计算机中因为取整的原因可能小于 a) (注, 这里log是以2为底)
所以, 2^log(a)> a/2
, 2^log(a)大于一半长度
-
所以, 我们查询某个区间
[l,r]
的最值(以最小值为例):区间长度
len = r - l + 1
,该区间最小值:
min(l往后2^log(len)的最小值, r往前2^log(len)的最小值)
-
因为,
k = log(len) > len/2
-
所以,前半部分l往后2^log(len)的最小值 =
mn[l][k]
-
要求 r往前2^log(len)的最小值, 首先要找到左端点x
x = r - (2^k-1)
-
所以,r往前2^log(len)的最小值 =
mn[x][k]
-
因此就可以求出最小值。
查询代码:
int query(int l, r)
{
int k = (int)(log((double)(r-l+1))/log(2.0));
x = r - (1<<k+1);
return min(mn[l][k], mn[x][k]);
}
由此看来查询时间为O(1);
参考
- rmp https://baike.baidu.com/item/rmq/1797559?fr=aladdin#2
- https://blog.csdn.net/Hanks_o/article/details/77547380
- https://www.cnblogs.com/qq965921539/p/9608980.html