zoukankan      html  css  js  c++  java
  • 数据结构学习笔记——ST表

    ST表

    导入

    RMQ(Range Mininum/Maxnum Query):即区间最值查询。对于长度为(N)的数组(A),有若干次询问(RMQ(i,j)),回答下标区间([i,j])内的最大/最小值。

    ST表可以很好地解决此类问题,预处理复杂度(O(NlogN)),查询(O(1))

    预处理

    (A[i])是要求区间最值的数组,(F[i][j])表示从第(i)个数起连续(2^j)个数中的最大值。

    显然初始化时要令(F[i][0]=A[i])

    除初始状态外,(F[i][j])表示的区间必有偶数个数字。将其均分为两段,一段为(F[i][j-1]),另一段为(F[i+2^{j-1}][j-1])。注意两段均包含(2^{j-1})个数字。

    则状态转移方程(以求区间最大值为例)

    [F[i][j]=max(F[i][j-1],F[i+2^{j-1}][j-1]) ]

    从而预处理出数组中所有长度为(2^j)((j=0,1...log_2N(向下取整)))的区间上的最值。

        //其实就是区间DP
    	for (int j = 1; j <= lg[n]; j++) {
            //枚举区间长度
            for (int i = 1; i + (1 << j) - 1 <= n; i++) {
                //枚举左端点i,区间长度为1<<j,则右端点就是i+(1<<j)-1,显然右端点不能超过n
                f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
            }
        }
    

    查询

    假设需要查询的区间为([l,r]),注意到区间重复是不影响结果的。如查询([1,5]),则查询(F[1][2])(区间([1,4])的最大值)和(F[2][2])(区间([2,5])的最大值)即可。

    换句话说,我们需要找到一个合适的(k),使得(l)起往右(2^k)个数不会超过(r),且从(r)起往左(2^k)个数不会超过(l),这样就可以从(F[l][k])(F[r-2^k+1][k])中得到区间([l,r])的最值。

    这个(k)显然和区间长度有关。查询区间的长度为(r-l+1),取(k=log_2(l-r+1))(向下取整),则这个(k)就是我们要找的合适的(k)

    则有:

    [RMQ(l,r)=max(F[l][k],F[r-2^k+1][k]) ]

        for (int i = 1; i <= m; i++) {
            int l, r; cin >> l >> r;
            int k = lg[r - l + 1];
            cout << max(f[l][k], f[r - (1 << k) + 1][k]);
        }
    

    另外(log_2i)的值同样可以预处理得出。(和倍增LCA的lg预处理不一样,不要混淆!这里是真正的(log_2i),那边是(log_2i+1)

        lg[0] = -1;
        for (int i = 1; i <= n; i++) {
            lg[i] = lg[i / 2] + 1;
        }
    

    完整代码

    const int maxn = 1e5 + 100;
    int a[maxn], f[maxn][22], lg[maxn];
    int main() {
        lg[0] = -1;
        n = read(); m = read();
        //洛谷模板题时间卡得很紧,全部用快读
        for (int i = 1; i <= n; i++) {
            a[i] = read();
            lg[i] = lg[i / 2] + 1;
        }
        for (int i = 1; i <= n; i++) {
            f[i][0] = a[i];
        }
        for (int j = 1; j <= lg[n]; j++) {
            //枚举区间长度
            for (int i = 1; i + (1 << j) - 1 <= n; i++) {
                //枚举左端点i,区间长度为1<<j,则右端点就是i+(1<<j)-1,显然右端点不能超过n
                f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
            }
        }
        for (int i = 1; i <= m; i++) {
            int l, r;
            l = read(); r = read();
            int k = lg[r - l + 1];
            printf("%d
    ", max(f[l][k], f[r - (1 << k) + 1][k]));
        }
        return 0;
    }
    
  • 相关阅读:
    delphi消息发送字符串
    Delphi2007 在Win10 下运行报错 Assertion failure
    python 定时器
    python 直接赋值 深浅拷贝
    python 闭包
    python 对象
    c++ sizeof和strlen
    c++入门笔记(一)
    python实现四种排序逻辑与代码
    webrtc autotest
  • 原文地址:https://www.cnblogs.com/streamazure/p/13889947.html
Copyright © 2011-2022 走看看