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算法
  • 相关阅读:
    (Good Bye 2019) Codeforces 1270B Interesting Subarray
    (Good Bye 2019) Codeforces 1270A Card Game
    Codeforces 1283D Christmas Trees(BFS)
    Codeforces 1283C Friends and Gifts
    Codeforces 1283B Candies Division
    1095 Cars on Campus (30)
    1080 Graduate Admission (30)
    1099 Build A Binary Search Tree (30)
    1018 Public Bike Management (30)
    1087 All Roads Lead to Rome (30)
  • 原文地址:https://www.cnblogs.com/qq188380780/p/7690779.html
Copyright © 2011-2022 走看看