跳转至

ST表

前置知识

倍增思想,二进制,对数

目标

了解 ST表的基本实现原理,会做模板题

What

RMQ问题(Range Maximum/Minimum Query),就是区间最值问题。

ST表(Sparse Table)是其中的一个算法。

Why

ST表是用于解决 可重复贡献问题 的数据结构。

给定一个长度为 n 的 序列,经过 \(O(nlogn)\)的预处理后,以 \(O(1)\) 的时间复杂度,在线回答 \([l, r]\) 区间的最值是多少。

ST表能维护的信息非常有限,不能较好地扩展,并且不支持修改操作。

How

1、预处理

img

// dp[i][j]表示数列在[i, i + 2 ^ j - 1]里的最大值
// 初始状态是 dp[i][0] = a[i]
// 递推公式 dp[i][j] = max(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1])

void ST_prework(){
    for (int i = 1; i <= n; i++) dp[i][0] = a[i];

    int Log = (int)log2(1.0 * n) + 1;
    for (int j = 1; j < Log; j++)
        for (int i = 1; i <= n - (1 << j) + 1; i++)
            dp[i][j] = max(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);
}

2、查询

img

// 询问时,
// 先计算出使得2^k 小于区间长度,且最大
// 那么,就可以用 "从 l 开始的2^k个数" 和 "以 r 结尾的2^k个数",这两段覆盖整个区间 [l, r]
// 即使有重叠也没关系

int ST_query(int l, int r){
    int k = (int)log2(1.0 * (r - l + 1));
    return max(dp[l][k], dp[r - (1 << k) + 1][k]);
}

3、什么是可重复贡献问题?

img

4、关于log的预处理

1使用cmath的log函数执行效率很高影响不大需要注意的是参数和返回值都是double
double log (double x);

2手动预处理
int Log[N];  // 预处理log

Log[1] = 0;
for (int i = 2; i <= n; i++) Log[i] = Log[i >> 1] + 1;

P3865 【模板】ST 表

题目链接:https://www.luogu.com.cn/problem/P3865

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;

int a[N], dp[N][20];
int n, m;

void ST_prework(){
    for (int i = 1; i <= n; i++) dp[i][0] = a[i];

    int Log = (int)log2(1.0 * n) + 1;
    for (int j = 1; j < Log; j++)
        for (int i = 1; i <= n - (1 << j) + 1; i++)
            dp[i][j] = max(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);
}

int ST_query(int l, int r){
    int k = (int)log2(1.0 * (r - l + 1));
    return max(dp[l][k], dp[r - (1 << k) + 1][k]);
}

int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    ST_prework();
    while (m--) {
        int l, r;
        scanf("%d%d", &l, &r);

        printf("%d\n", ST_query(l, r));
    }

    return 0;
}

题单

P3865 【模板】ST 表

POJ3368 -- Frequent values

P2880 USACO07JAN Balanced Lineup G

总结

ST表是一个很好的用来理解倍增思想的一个算法。代码简洁,易用。

参考

RMQ ---- ST(Sparse Table)算法

oi-wiki