Sparse Table - 离线区间最值
Sparse Table
Sparse Table是一种简单的离线数据结构,主要用于解决RMQ(Range Maximum/Minimum Query, 区间最值查询)问题。它主要应用倍增的思想,可以实现 \(O(nlogn)\) 预处理、 \(O(1)\) 查询。
ST使用一个二维数组 \(f\) ,先预处理范围内所有的 \(f[a][b] = \max ({A_{i}})_{i\in[a, a+2^b-1]}\)。查询时再利用这些子区间算出待求区间的最大值。
具体的查询方法:对于区间 $[l, r] $,我们取其两个等长的连续子区间将其覆盖。注意,这两个子区间不一定交集为空。由于区间的长度为 \(r-l+1\) ,而我们预处理的\(f\)数组将区间划分为 \(2\) 的整数倍,因此可以将区间 \([l,r]\) 拆分为两个长度为 \(2^{\lfloor{log_2{(r-l+1)}\rfloor}}\)的子区间 ,分别为 \([l, l+2^s-1]\) 和 \([r-2^s+1,r]\) 。
代码如下
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
int n, m, l, r;
int f[N][21]; // 第二维根据数据范围决定, 不小于log(N)
int Log2[N];
int main(){
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i){
scanf("%d", &f[i][0]);
}
for(int i = 1; i <= n; ++i){ // dim 2
for(int j = 1; j + (1 << i)-1 <= n; ++j){ // dim 1
f[j][i] = max(f[j][i-1], f[j+(1<<(i-1))][i-1]);
}
}
for(int i = 2; i <= n; ++i){
Log2[i] = Log2[i/2] + 1;
}
while(m--){
scanf("%d%d", &l, &r);
int s = Log2[r-l+1];
printf("%d\n", max(f[l][s], f[r-(1<<s)+1][s]));
}
system("pause");
return 0;
}
其实ST表不仅能处理最大值/最小值,凡是符合结合律且可重复贡献的信息查询都可以使用ST表高效进行。什么叫可重复贡献呢?设有一个二元运算 \(f(x,y)\) ,满足 \(f(a,a)=a\) ,则 \(f\) 是可重复贡献的。显然最大值、最小值、最大公因数、最小公倍数、按位或、按位与都符合这个条件。可重复贡献的意义在于,可以对两个交集不为空的区间进行信息合并。
---- suffer now and live the rest of your life as a champion ----