RMQ算法 (ST算法)

 概述:

  RMQ(Range Minimum/Maximum Query),即区间最值查询,是指这样一个问题:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j之间的最小/大值。对于一次查询,可以暴力地O(n),但是当查询次数很多的时候,这样的暴力就无法进行了。这时我们可以通过RMQ算法来解决这个问题。

RMQ(ST):(关于学习RMQ的博客:框架即讲解比较详细具体代码比较好

  ST(Sparse Table)算法是一个非常有名的在线处理RMQ问题的算法,它可以在O(nlogn)时间内进行预处理,然后在O(1)时间内回答每个查询。

  首先是预处理,用动态规划(DP)解决。设A[i]是要求区间最值的数列,F[i, j]表示从第i个数起连续2^j个数中的最大值。例如数列3 2 4 5 6 8 1 2 9 7,F[1,0]表示第1个数起,长度为2^0=1的最大值,其实就是3这个数。 F[1,2]=5,F[1,3]=8,F[2,0]=2,F[2,1]=4……从这里可以看出F[i,0]其实就等于A[i]。这样,DP的状态、初值都已经有了,剩下的就是状态转移方程。我们把F[i,j]平均分成两段(因为f[i,j]一定是偶数个数字),从i到i+2^(j-1)-1为一段,i+2^(j-1)到i+2^j-1为一段(长度都为2^(j-1))。用上例说明,当i=1,j=3时就是3,2,4,5 和 6,8,1,2这两段。F[i,j]就是这两段的最大值中的最大值。于是我们得到了动态规划方程F[i, j]=max(F[i,j-1], F[i + 2^(j-1),j-1])。

然后是查询。取k=[log2(j-i+1)],则有:RMQ(A, i, j)=min{F[i,k],F[j-2^k+1,k]}。 举例说明,要求区间[2,8]的最大值,就要把它分成[2,5]和[5,8]两个区间,因为这两个区间的最大值我们可以直接由f[2,2]和f[5,2]得到。

void ST(int N)
{
    for(int i=1;i<=N;i++) dp[i][0] = vec[i];
    for(int j=1;(1<<j) <= N;j++)
    {
        for(int i=1;i+(1<<j)-1<=N;i++)
        {
            dp1[i][j] = max(dp[i][j-1],dp[i+(1<<j-1)][j-1]); //由于移位操作的优先度低,1<<j-1 = 1<<(j-1);
        }
    }
}
int RMQ(int l,int r)
{
    int k = 0;
    while((1<<k+1) <= r-l+1) k++;
    return max(dp1[l][k],dp1[r-(1<<k)+1][k]);
}

POJ-2364

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 using namespace std;
 5 const int MAX_N = 5e4+9;
 6 const int INF = 1e9+7;
 7 int vec[MAX_N];
 8 int dp1[MAX_N][25];
 9 int dp2[MAX_N][25];
10 void ST(int N)
11 {
12     for(int i=1;i<=N;i++) dp1[i][0] = dp2[i][0] = vec[i];
13     for(int j=1;(1<<j)<=N;j++)
14     {
15         for(int i=1;i+(1<<j)-1 <= N;i++)
16         {
17             dp1[i][j] = max(dp1[i][j-1],dp1[i+(1<<j-1)][j-1]);
18             dp2[i][j] = min(dp2[i][j-1],dp2[i+(1<<j-1)][j-1]);
19         }
20     }
21 }
22 int RMQ(int l,int r)
23 {
24     int k = 0;
25     while((1<<k+1) <= r-l+1) k++;
26     return max(dp1[l][k],dp1[r-(1<<k)+1][k]) - min(dp2[l][k],dp2[r-(1<<k)+1][k]);
27 }
28 int main()
29 {
30     int N,M,T;
31     while(cin>>N>>M)
32     {
33         for(int i=1;i<=N;i++)
34         {
35             scanf("%d",&vec[i]);
36         }
37         ST(N);
38         for(int i=0;i<M;i++)
39         {
40             int l,r;
41             scanf("%d%d",&l,&r);
42             int ans = RMQ(l,r);
43             printf("%d\n",ans);
44         }
45     }
46     return 0;
47 }

原文地址:https://www.cnblogs.com/doggod/p/8375923.html

时间: 2024-10-15 22:17:44

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问题&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算法

什么是RMQ.ST:RMQ(Range Minimum/Maximum Query)问题,即求区间的最值.可以写一个线段树来实现,但是每次查询的时间复杂度为O(log n),若查询次数过多则可能超时.ST算法是一种离线算法,经过O(nlogn)的预处理后,可以在O(1)的时间复杂度内进行查询,缺点是无法对数据做出修改. 算法实现: 初始化:用dp实现初始化.a[]为原始数据数组f,[i][j]表示从i向后的2j个数字中的最值.显然f[i][0]=a[i]; 我们将f[i][j]分为两段,一段为a

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]\)分为\

LCA在线算法ST算法

求LCA(最近公共祖先)的算法有好多,按在线和离线分为在线算法和离线算法. 离线算法有基于搜索的Tarjan算法较优,而在线算法则是基于dp的ST算法较优. 首先说一下ST算法. 这个算法是基于RMQ(区间最大最小值编号)的,不懂的可以这里学习一些 而求LCA就是把树通过深搜得到一个序列,然后转化为求区间的最小编号. 比如说给出这样一棵树. 我们通过深搜可以得到这样一个序列: 节点ver 1 3 1 2 5 7 5 6 5 2 4 2 1 (先右后左) 深度R 1 2 1 2 3 4 3 4 3

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