ST表
给定一个长度为
n
n
n 的序列,查询
q
q
q 次
[
a
l
.
.
.
a
r
]
[a_l...a_r]
[al...ar]的极值。(RMQ问题)
(比线段树的常数小,代码简短。但是不支持修改且只能用于查询极值)
1.
f
[
i
]
[
j
]
f[i][j]
f[i][j] 表示第
i
i
i 个数到往后
2
j
2^j
2j 范围内(包括自身) 的极值
2.需要用
n
∗
l
o
g
n
n*logn
n∗logn的预处理 处理出
f
[
i
]
[
j
]
f[i][j]
f[i][j] 所储存的信息,转移过程取极值是利用
倍
增
倍增
倍增原理。
3.查询区间长度为
L
L
L 时, 令
k
=
log
2
L
k=\log_2 L
k=log2L,把原区间分为
[
l
,
l
+
2
k
]
[l,l+2^k]
[l,l+2k]和
[
r
−
2
k
+
1
,
r
]
[r-2^k+1,r]
[r−2k+1,r]。两个区间的长度大小都是
2
k
2^k
2k.两个区间的最值即为原区间最值。
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
int n,m,l,r;
int f[101010][20];
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++)
scanf("%d",&f[i][0]);
for(int i = 1; i <= 20; i++)
for(int j = 1; j+(1<<i)-1 <= n; j++)
f[j][i] = max(f[j][i-1], f[j+(1<<i-1)][i-1]);
for(int i = 1; i <= m; i++)
{
scanf("%d%d",&l,&r);
int k = log(r-l+1) / log(2);
printf("%d\n",max(f[l][k], f[r-(1<<k)+1][k]));
}
return 0;
}