zoukankan      html  css  js  c++  java
  • RMQ问题之ST算法

    RMQ问题:求长度为n的数列中,求[i,j]直接的最值。

    ST算法:一种动态规划的方法。

    一、预处理dp数组

    对于区间[i,i+2^j-1]的最值,只需要知道区间[i,i+2^(j-1)-1]和区间[i+2^(j-1),i+2^j-1]的最值即可。

      由此可的递推方程:dp[i,i+2^j-1] = max(dp[i,i+2^(j-1)-1],dp[i+2^(j-1),i+2^j-1])

    但是对于一个比较长的数列,2^j是一个非常大的数,我们也可发现,没什么必要直接记录左右端点。

    优化为i记录一个起点,j记录类似距离的东西,dp[i,j]表示区间[i,i+2^j-1]。

      优化后递推方程:dp[i,j] = max(dp[i,j-1],dp[i+2^(j-1),j-1])

    预处理dp数组时间复杂度为O(nlogn)。

    二、查询最值

    所以开始把一个区间当dp数组求出来,再进行查询即可。

    但是查询时候,知道的是两个端点l,r。

    对于区间[l,r],如何再dp数组中查询呢?

    前面讲了i表示起点,j代表类似距离的东西。

    很明显l就是i了。可是2^j-1不可能是r,这时候就要找个中间的"j"了。

    令len = r-l+1, 则2^k <= len(此处注意不是2^k-1,反证:当2^k-1 == len时,l + 2^k-1 = l + len = r + 1 > r)

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

    查询时间复杂度为O(1)。

    尽管代码比较简洁并且功能比较强大,速度也比较快,可是并没有线段树那么功能多。

     1 #include <cstdio>
     2 #include <cmath>
     3 #include <iostream>
     4 using namespace std;
     5 const int maxn = 100005;
     6 int ma[maxn][20];
     7 int mi[maxn][20];
     8 int a[maxn];
     9 void init(int n){
    10     for(int i = 1; i <= n; ++i)
    11         ma[i][0] = mi[i][0] = a[i];
    12     for(int j = 1; (1<<j) <= n; ++j)
    13         for(int i = 1; i+(1<<j)-1 <= n; ++i){
    14             ma[i][j] = max(ma[i][j-1], ma[i+(1<<(j-1))][j-1]);
    15             mi[i][j] = min(mi[i][j-1], mi[i+(1<<(j-1))][j-1]);
    16         }
    17 }
    18 int rmq_max(int l, int r, int k){
    19     return max(ma[l][k], ma[r-(1<<(k))+1][k]);
    20 }
    21 int rmq_min(int l, int r, int k){
    22     return min(mi[l][k], mi[r-(1<<(k))+1][k]);
    23 }
    24 int rmq(int l, int r){
    25     int k = 0;
    26     while(1<<(k+1) <= r-l+1)
    27         ++k;
    28     //int k = (int)(log(1.0*(r-l+1))/log(2.0));//也可以直接算出k
    29     //算出k后,具体情况进行调用函数计算。例如返回最大差值.
    30     return rmq_max(l,r,k) - rmq_min(l,r,k);
    31 }
    32 int main(){
    33     int n,q;
    34     scanf("%d%d",&n,&q);//n个数,q次查询次数
    35     for(int i = 1; i <= n; ++i)//输入n个数
    36         scanf("%d",a+i);
    37     init(n); int l,r;
    38     while(q--){//进行q次查询
    39         scanf("%d%d",&l,&r);
    40         printf("%d
    ",rmq(l,r));
    41     }
    42     return 0;
    43 }
    ST算法
  • 相关阅读:
    easyUI的formatter使用
    tomcat的CATALINA_HOME可以不用设置
    关于json解析中 解析多重json对象
    "i++"和"++i"浅析
    poj1050 To the Max(降维dp)
    2017年暑假ACM集训日志
    codevs1228 (dfs序+线段树)
    密钥登录服务器
    使用iwd联网
    idea和gradle创建android遇到的网络问题
  • 原文地址:https://www.cnblogs.com/qq188380780/p/7690779.html
Copyright © 2011-2022 走看看