Sparse Table

Sparse Table

Sparse Table是一种简单的离线数据结构,主要用于解决RMQ(Range Maximum/Minimum Query, 区间最值查询)问题。它主要应用倍增的思想,可以实现 (O(nlogn)) 预处理、 (O(1)) 查询。

ST使用一个二维数组 (f) ,先预处理范围内所有的 (f[a][b] = max ({A_{i}})_{iin[a, a+2^b-1]})。查询时再利用这些子区间算出待求区间的最大值。

具体的查询方法:对于区间 $[l, r] $,我们取其两个等长的连续子区间将其覆盖。注意,这两个子区间不一定交集为空。由于区间的长度为 (r-l+1) ,而我们预处理的(f)数组将区间划分为 (2) 的整数倍,因此可以将区间 ([l,r]) 拆分为两个长度为 (2^{lfloor{log_2{(r-l+1)} floor}})的子区间 ,分别为 ([l, l+2^s-1])([r-2^s+1,r])

preview

代码如下

#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
", 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 ----
原文地址:https://www.cnblogs.com/popodynasty/p/14709311.html