zoukankan      html  css  js  c++  java
  • 简要理解ST表

    ST表

    • 注:ST表需要用到倍增算法;ST表实质上是一种DP

    ST表的作用

    • 快速查询区间最大值和区间最小值

    前提:倍增

    • 我们读入了一个长度为n的数列,用a[1]a[n]存储。然后我们不由分说地先算出数列中第1n-1个数的 后两个数(包括它自身)中的最大值,比如说,第一个数后两个数的最大值=max(a[1],a[2])。a[n+1]不存在,所以
      不用计算a[n]后两个数的最大值,计算到a[n-1]就可以(而且必须)停下来了

    • 然后我们再算出数列中第1~n-3个数的 后四个数(包括它自身)中的最大值,可以再枚举一遍,但我们有先前算好的结果可以利用:第一个数后四个数的最大值=max(第一个数后两个数的最大值,第三个数后两个数的最大值)

    • 依次类推,第一个数后八个数的最大值=max(第一个数后四个数的最大值,第五个数后四个数的最大值),第一个数后十六个数的最大值=max(第一个数后八个数的最大值,第九个数后八个数的最大值),……

    正题:ST表

    • 定义一个数组st[n][x]存储这些值,st[i][j]表示第i个数后面的2j(即1<<j)个数(包括第i个数自身)中的最大值,x可以用符合2x<=n的最大x值(+10防越界),也可以自己定义一个足够用的值(+10防越界)
    • st[i][0] 即为 a[i],可以用 st[i][0] 代替 a[i] 存储数列
    for(int j = 1;j <= x; ++j ){
    	for(int i = 1;i <= n - (1<<j) +1 ; ++ i){
    		st[i][j] = std::max(st[i][j-1],st[i+(1<<(j-1))][j-1]);
    	}
    }
    

    解释

    • j的循环在最外面

    根据转移方程 st[i][j] = max(st[i][j-1],st[i+(1<<(j-1))][j-1])(i<=n-2^j+1,1<=j<=x),只有算出所有的st[i][j-1],才能计算st[i][j]。

    • i<=n-(1<<j)+1

    计算a[i]到a[j]之间的最大值,防止越界,最多只能枚举到a[i]~a[n],
    此时n-i+1=2j(即1<<j),i=n-2j+1,所以1<=i<=n-(1<<j)+1。

    使用

    • 不断分割查询区间,直到剩下的区间长度为0,并把所有分割数的区间对应的最大值 一 一比较
    • j从x向1枚举,直到(1<<j)<=区间长度,分割并结束循环,即每次只分割 大于区间长度的一半小于等于区间长度 的一段
    int search(int l,int len,int r)
    {
        if(l>r) return -0x3f3f3f3f;
        if(len<=0) return -0x3f3f3f3f;
        for(int i=25;i>=0;--i){
            if( (1<<i) <=len )
                return std::max(t[l][i],search(l+(1<<i),len-(1<<i),r));
        }
    }
    

    拓展

    • 最小值当然也可以,注意search查询越界返回的极小值换成极大值就行
  • 相关阅读:
    不定方程(Exgcd)
    [模板]乘法逆元
    STL-Deque(双端队列)与单调队列的实现
    最优得分 score
    摆书 book
    [模板]树链剖分
    [模板]Splay
    NOIP2013 货车运输
    Java的类类型和类的动态加载
    Java:搜索特定后缀名的文件
  • 原文地址:https://www.cnblogs.com/StarOnTheWay/p/10383448.html
Copyright © 2011-2022 走看看