ST表模板
ST表:一种利用dp求解区间最值的倍增算法。它是解决RMQ问题(区间最值问题)的一种强有力的工具,它可以做到 O ( n l o g n ) O(nlogn) O(nlogn)预处理, O ( 1 ) O(1) O(1)查询最值
RMQ问题:给定一个长度为N的区间,M个询问,每次询问Li到Ri这段区间元素的最大值/最小值。如果暴力找最大值,复杂度是o(n)。但如果查询多次,这个复杂度就很大了。解决这个问题的方法是离线ST表和支持在线修改的线段树。
了解具体算法推荐阅读这篇题解冲冲冲 _
1. 题目
题目描述
给定一个长度为 N 的数列,和 M 次询问,求出每一次询问的区间内数字的最大值。
输入格式
第一行包含两个整数 N, M ,分别表示数列的长度和询问的个数。
第二行包含 N 个整数(记为 a i a_i ai),依次表示数列的第 i 项。
接下来 M行,每行包含两个整数 l i , r i l_i, r_i li,ri,表示查询的区间为 [ l i , r i ] [ l_i, r_i] [li,ri]
输出格式
输出包含 M 行,每行一个整数,依次表示每一次询问的结果。
2. ST表模板
核心思想就是
f
[
i
]
[
j
]
f[i][j]
f[i][j]代表区间
[
i
,
i
+
2
j
−
1
]
(
2
j
个
数
)
[i, i + 2^{j} - 1](2^{j}个数)
[i,i+2j−1](2j个数) 中的最大值,这样我们就能使用如下的状态转移方程:
f
[
i
]
[
j
]
=
m
a
x
{
f
[
i
]
[
j
−
1
]
,
f
[
i
+
2
j
−
1
]
[
j
−
1
]
}
f[i][j] = max\left\{ f[i][j-1], f[i+2^{j-1}][j-1] \right\}
f[i][j]=max{f[i][j−1],f[i+2j−1][j−1]}
代码非常简单~ 如下 😃
#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;
#define N 1100
int f[N][21] = { 0 };
inline int readInt() {
int temp = 0;
char ch;
while (!isdigit(ch = getchar()));
while (isdigit(ch)) {
temp = 10 * temp + ch - '0';
ch = getchar();
}
return temp;
}
int main()
{
int n, m, l, r, k;
n = readInt();
m = readInt();
for (int i = 1; i <= n; i++) {
f[i][0] = readInt();
}
for (int j = 1; j <= 17; j++) {
for (int i = 1; i + (1 << (j - 1)) <= n; i++) {
f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
}
}
for (int i = 0; i < m; i++) {
l = readInt();
r = readInt();
k = log2((r - l + 1));
printf("%d\n", max(f[l][k], f[r - (1 << k) + 1][k]));
}
return 0;
}
双倍经验:洛谷P2251 质量检测