基于稀疏表(Sparse Table)的RMQ需要先进行复杂度O(nlogn)的预处理,而后在查询[ql, qr]的最值时,计算出最大的满足ql + (1 << bit) <= qr的bit(复杂度O(loglogn)),即可在O(1)时间复杂度内查询,从而可以解决查询次数很多(如大于100万)的RMQ问题。
我们定义t[i][j]为以 i 为左端点的长度为 2j 的闭区间(0 <= j, 2j <= n, 1 <= i <= n - 2j + 1)
我们可以得到如下的一个稀疏表
这样以来每个t[][]表示的都是一段长度为2的幂次的区间的最值。但考虑到实际查询的区间长度往往不是2的幂次,那么这个区间要如何表示呢?答案是一个不行,就来两个。把查询区间用两个区间的并来表示。为了确保两个区间的并恰好为查询区间,我们可以从左右边界向中间扫(如图)
那么为了确保两个小区间可以包含整个大区间,小区间长度必然不小于原区间的一半,且区间长度为2的幂次。所以在RMQ中,我们首先要求出满足2j <= qr - ql < 2j + 1 的j。也就是使得2j不超过(qr - ql)的最大的j。
有了这种划分区间的思想,我们可以轻易地出状态转移公式
t[i][j] = {t[i][j - 1], t[i + (1 << (j - 1))][j - 1]};
对于每个查询,{dp[ql][j], dp[qr - (1 << j) + 1][j])就是答案了。//左右皆闭
这样以来问题就仅剩下,如何高效地求解对应j呢?
计算(qr - ql),然后二分求解即可
1 int mbit(int a) { 2 int l = 0, r = 16; 3 while (l < r - 1) { 4 int m = (l + r) / 2; 5 if ((1 << m) <= a) { 6 l = m; 7 } else { 8 r = m; 9 } 10 } 11 return l; 12 }