RMQ(区间最值问题)

Range Maxinum/Mininum Query(又称ST表)可以通过dp+倍增预处理的方式从而达到 O(nlogn)O(n \log n) 的构建预处理,O(1)O(1) 的查询。

初始化

我们可以通过先定义一个二维数组 fi,jf_{i, j}表示从第 ii个数开始的区间大小为 jj 的最值。而由于一个区间的最值 fi,jf_{i, j} 可以通过这个区间的两部分 fi,j1fi+2j1,j1f_{i, j - 1} 和 f_{i + 2 ^ {j - 1}, j - 1}得到,从而可以得到状态转移方程:

fi,j=max/min(fi,j1,fi+2j1,j1)f_{i, j} = \max/\min(f_{i, j - 1}, f_{i + 2 ^{j - 1}, j - 1})

数组的第一维范围为数据的最大范围 nn,第二维为数据最大范围的 log2n\log_{2} n。因此构造的时间复杂度为 O(nlogn)O(n \log n)。代码如下

1
2
3
4
5
6
void init()
{
for (int j = 1; j < M; j++)
for (int i = 1; i + (1 << j) - 1 <= n; i++)
f[i][j] = min(f[i][j - 1], f[i + (1 << j - 1)][j - 1]);
}

区间查询

如果查询的区间为 [l,r][l, r],那么令 kk 为所求的 log\log 数值,即 k=log2(rl+1)k = \lfloor \log_{2} (r - l + 1) \rfloor,从而 2k+1rl+12 ^ {k + 1} \geq r - l + 1

故可得答案 ansans 为:

ans=min/max(sl,k,sr2k+1,k)ans = \min / \max (s_{l, k}, s_{r - 2^{k} + 1, k})

1
2
3
4
5
6
int query(int l, int r)
{
int len = r - l + 1;
int k = log2(len);
return min(f[l][k], f[r - (1 << k) + 1][k]);
}