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]\)

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\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\) 是可重复贡献的。显然最大值、最小值、最大公因数、最小公倍数、按位或、按位与都符合这个条件。可重复贡献的意义在于,可以对两个交集不为空的区间进行信息合并。

posted @ 2021-04-27 15:51  popozyl  阅读(98)  评论(0编辑  收藏  举报