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\n",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,输出从a到b的最大的数和最小的数的差。

     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\n",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 }
时间: 2024-12-17 09:00:30

RMQ问题——ST算法的相关文章

RMQ的ST算法

·RMQ的ST算法    状态设计:        F[i, j]表示从第i个数起连续2^j个数中的最大值    状态转移方程(二进制思想):        F[i, j]=max(F[i,j-1], F[i + 2^(j-1),j-1])    查询时:        因为这个区间的长度为j - i + 1,所以我们可以取k=log2( j - i + 1),        则有:RMQ(A, i, j)=max{F[i , k], F[ j - 2 ^ k + 1, k]}.

RMQ(ST算法)

RMQ(Range Minimum/Maximum Query),即区间最值查询,是指这样一个问题:对于长度为n的数列a,回答若干询问RMQ(A,i,j)(i, j<=n),返回数列a中下标在i,j之间的最小/大值.如果只有一次询问,那样只有一遍for就可以搞定,但是如果有许多次询问就无法在很快的时间处理出来.在这里介绍一个在线算法.所谓在线算法,是指用户每输入一个查询便马上处理一个查询.该算法一般用较长的时间做预处理,待信息充足以后便可以用较少的时间回答每个查询.ST(Sparse Table

RMQ问题ST算法

1. 概述 RMQ(Range Minimum/Maximum Query),即区间最值查询,是指这样一个问题:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j之间的最小/大值.这两个问题是在实际应用中经常遇到的问题,下面介绍一下解决这两种问题的比较高效的算法.当然,该问题也可以用线段树(也叫区间树)解决,算法复杂度为:O(N)~O(logN),这里我们暂不介绍. 2.RMQ算法 对于该问题,最容易想到的解决方案是遍历,复杂度是O(n).但当数据量

RMQ问题 ST算法

RMQ是询问某个区间的最大值或最小值的问题,主要求解方法之一ST算法: ST算法其实是倍增思想的产物,等下看代码实现就很明显了 ST算法通常用在要多次询问一些区间的最值的问题中,相比于线段树,它的程序实现更简单,运行速度更快; ST算法没有修改操作(或者说不擅长动态修改) ST算法流程: 预处理:ST算法的原理实际上是动态规划,我们用a数组表示一组数,设\(f[i,j]\)表示从\(a[i]\)到\(a[i+2^j-1]\)这个范围内的最大值,从中间平均分成两部分,即把\(f[i,j]\)分为\

[总结]RMQ问题&amp;ST算法

目录 一.ST算法 二.ST算法の具体实现 1. 初始化 2. 求出ST表 3. 询问 三.例题 例1:P3865 [模板]ST表 例2:P2880 [USACO07JAN]平衡的阵容Balanced Lineup 一.ST算法 ST算法(Sparse Table Algorithm)是用于解决RMQ问题(区间最值问题,即Range Maximum/Minimum Question)的一种著名算法. ST算法能在复杂度为\(O(NlogN)\)的预处理后,以\(O(1)\)的复杂度在线处理序列区

RMQ之ST算法模板

1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 using namespace std; 5 const int N=1e6+111; 6 int Max[N][21],Min[N][21],a[N]; 7 void ST(int *a,int n)//预处理,O(NlogN) 8 { 9 for(int i=1;i<=n;i++) 10 Min[i][0]=Max[i][0]=a[i

RMQ问题ST算法 (还需要进一步完善)

/* RMQ(Range Minimum/Maximum Query)问题: RMQ问题是求给定区间中的最值问题.当然,最简单的算法是O(n)的,但是对于查询次数很多(设置多大100万次),O(n)的算法效率不够.可以用线段树将算法优化到O(logn)(在线段树中保存线段的最值).不过,Sparse_Table算法才是最好的:它可以在O(nlogn)的预处理以后实现O(1)的查询效率.下面把Sparse Table算法分成预处理和查询两部分来说明(以求最小值为例). 预处理: 预处理使用DP的思

RMQ之ST算法

1 #include <stdio.h> 2 #include <string.h> 3 const int N = 100; 4 int a[N]; 5 int dp[N][33]; 6 inline int min(const int &a, const int &b) 7 { 8 return a < b ? a : b; 9 } 10 11 /* 12 dp[i][j] 表示以i开头的,长度为2^j的区间中的最小值 13 很明显dp[i][0] = a

RMQ问题与ST算法

RMQ(Range Minimum/Maximum Query)问题是求区间最值问题. 对于长度为 n 的数组 A,进行若干次查询,对于区间 [L,R] 返回数组A中下标在 [L,R] 中的最小(大)值. 可以用线段树来解决这个问题,预处理的复杂度是 O(nlogn),查询的复杂度是 O(logn). 更好的解法是ST算法.Sparse_Table算法,即稀疏表算法,这个方法可以在 O(nlogn) 的预处理后达到 O(1) 的查询代价. 这个算法非常容易实现. 定义 F[ i, k ] 表示从