• RMQ问题——ST算法


    1. 什么是RMQ、ST:RMQ(Range Minimum/Maximum Query)问题,即求区间的最值。可以写一个线段树来实现,但是每次查询的时间复杂度为O(log n),若查询次数过多则可能超时。ST算法是一种离线算法,经过O(nlogn)的预处理后,可以在O(1)的时间复杂度内进行查询,缺点是无法对数据做出修改。
    2. 算法实现:

      初始化:用dp实现初始化。a[]为原始数据数组f,[i][j]表示从i向后的2j个数字中的最值。显然f[i][0]=a[i];

      我们将f[i][j]分为两段,一段为a[i]~a[2j-1]的最值即f[i][j-1],一段为a[i+2j-1]~a[i+2j]即f[i+1<<(j-1)][j-1];这样就得到了状态转移方程f[i][j]=max/min(f[i][j-1],f[i+1<<(j-1)][j-1]);。

       dp数组即f数组;

       1         for(i=1;i<=n;i++){
       2             dpmax[i][0]=a[i];
       3             dpmin[i][0]=a[i];//初始化
       4         };
       5         int end_j=log(n+0.0)/log(2.0);//计算j的最大值
       6         int endi;
       7         for(j=1;j<=end_j;j++){//注意,由于每一个dp[i,j]的求解都要用到dp[i,j-1]故j应放在外层循环
       8             endi=n+1-(1<<j);//计算i的最大值
       9             for(i=1;i<=endi;i++){
      10                 dpmax[i][j]=max(dpmax[i][j-1],dpmax[i+(1<<(j-1))][j-1]);
      11                 dpmin[i][j]=min(dpmin[i][j-1],dpmin[i+(1<<(j-1))][j-1]);//dp预处理
      12             }
      13         }

      查询:得到f数组之后,若要查询[l,r]的最值,则将区间分成两段,l~log2r与r-log2r~r,则两段的最值中较大(小)的即为答案。

      1         for(i=1;i<=m;i++){
      2             scanf("%d%d",&l,&r);
      3             k=log(r-l+1.0)/log(2.0);//计算分割点
      4             printf("%d
      ",max(dpmax[l][k],dpmax[r-(1<<k)+1][k])//分两段查询
      5                     -min(dpmin[l][k],dpmin[r-(1<<k)+1][k]));
      6         }
    3. 例题:POJ3264

      题目大意:给出一串的数字,然后给出一个区间a b,输出从ab的最大的数和最小的数的差。

       1 #include<iostream>
       2 #include<cmath>
       3 #include<cstring>
       4 #include<cstdio>
       5 using namespace std;
       6 
       7 int a[100000],dpmax[50000][100],dpmin[50000][100];
       8 
       9 int main(){
      10     std::ios::sync_with_stdio(false);
      11     int i,j,m,n,k,t,l,r;
      12     while(scanf("%d%d",&n,&m)!=EOF){
      13         for(i=1;i<=n;i++)scanf("%d",&a[i]);
      14         for(i=1;i<=n;i++){
      15             dpmax[i][0]=a[i];
      16             dpmin[i][0]=a[i];//初始化
      17         };
      18         int end_j=log(n+0.0)/log(2.0);//计算j的最大值
      19         int endi;
      20         for(j=1;j<=end_j;j++){//注意,由于每一个dp[i,j]的求解都要用到dp[i,j-1]故j应放在外层循环
      21             endi=n+1-(1<<j);//计算i的最大值
      22             for(i=1;i<=endi;i++){
      23                 dpmax[i][j]=max(dpmax[i][j-1],dpmax[i+(1<<(j-1))][j-1]);
      24                 dpmin[i][j]=min(dpmin[i][j-1],dpmin[i+(1<<(j-1))][j-1]);//dp预处理
      25             }
      26         }
      27         for(i=1;i<=m;i++){
      28             scanf("%d%d",&l,&r);
      29             k=log(r-l+1.0)/log(2.0);//计算分割点
      30             printf("%d
      ",max(dpmax[l][k],dpmax[r-(1<<k)+1][k])//分两段查询
      31                     -min(dpmin[l][k],dpmin[r-(1<<k)+1][k]));
      32         }
      33         return 0;
      34     }
      35 }
  • 相关阅读:
    Spring配置通过动态工厂方法创建的bean
    Spring配置通过静态工厂方法创建的bean
    SpringMVC针对post请求乱码的处理
    SpringMVC的HelloWorld快速入门!
    SpringMVC和Spring的关系
    pageContext、request、session和application区别
    orcale 实现 sql server 里面的表值函数SPLIT
    查询语句有 or 会导致查询速度变慢问题解决
    用谷歌浏览器以及插件 测试接口
    OraCle 记录 实现 sql中的 for xml path ('')
  • 原文地址:https://www.cnblogs.com/y-m-y/p/5719813.html
Copyright © 2020-2023  润新知