ST表

近期我计划要补更好多noip知识点

就先从ST表开始吧

ST表是一种编程复杂度低的用于求解RMQ问题的算法

算法核心思想运用了动态规划和倍增

以求区间最大值为例

设a[i][j]表示左端点为i ,右端点为i + (2 ^ j) - 1的区间的最大值

显然这段区间的长度为2 ^ j;

然后将这段区间分为两段长度均为2 ^ (j - 1)的子区间

一段为a[i][j - 1],另一端为a[i + 2 ^ (j - 1)][j - 1]

所以原区间的最大值就是两个子区间最大值的较大的值

至此可以写出dp的动态转移方程:

当j == 0时 a[i][0] = 输入的序列中的第i个(即r[i]);

当j > 0时 a[i][j] = max(a[i][j - 1], a[i + 2 ^ (j - 1)][j - 1]);

至于数组a的大小要特殊说明一下

第一维的大小为输入序列的最大长度len

第二维的大小为loglen(一般开到25 ~ 30均可)

接下来上一道例题:洛谷P3865【模板】ST表 

下面是我的代码

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<cmath>
#include<string>
#include<iostream>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 5;
int a[maxn][25], n, m;
int read()
{
    int ans = 0, op = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-') op = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        ans *= 10;
        ans += ch - '0';
        ch = getchar();
    }
    return ans * op;
}
void ST()
{
    for(int i = 1;i <= n;i++) a[i][0] = read();
    for(int j = 1;j <= 19;j++)
    {
        for(int i = 1;i + (1 << j) - 1 <= n;i++) a[i][j] = max(a[i][j - 1], a[i + (1 << (j - 1))][j - 1]);
    }
}
int query(int l, int r)
{
    int k = log2(r + 1 - l);
    return max(a[l][k], a[r - (1 << k) + 1][k]);//如需求区间最大值则将max改为min 
}
int main()
{
    int n = read(), m = read();
    ST();
    while(m--)
    {
        int L, R;
        L = read(), R = read();
        printf("%d
", query(L, R));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/thx666/p/9755106.html