RMQ问题之ST算法

RMQ问题之ST算法

RMQ(Range Minimum/Maximum Query)问题,即区间最值问题。
给你n个数,a1 , a2 , a3 , ... ,an,求出区间 [ l , r ]的最大值。

举例:
a={ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 },求出区间[4 ,8]中的最值。(答案:8 )

这个问题最朴素的想法是用一个循环每次比较大小,但是,当数据范围较大时,这个算法十分低效。这时我们往往使用 ST 算法解决这个问题。虽然线段树和树状数组都能解决,但是ST算法更快。ST算法能做到O(1)时间的查询,而且代码实现更容易。

我们定义 f ( i , j ) 表示从i开始,长度为 2j 的一段区间中的最大值。

例如:在数列3,2,4,5,6,8,1,2,9,7中,f ( 1 , 0 )表示从第一个数开始长度为20的区间内的最大值,即f ( 1 , 0 ) = 3 , 同理f ( 1 , 1 )=3 , f ( 1 , 2 ) =5, f ( 1 , 3 ) =8。从这里很容易发现,f ( i , 0 ) 等于原数列第i个数的值。

可以通过预处理的递推计算f ( i , j ):

f ( i , j ) = max { f[i][j-1] , f[i+(1<<j-1)][j-1] }

这个方程与动态规划的思想十分相似,这几乎是ST算法的核心,但是,这个方程是什么意思呢?我们将区间[ i , j ]分成两部分[ i , i+2j-1 -1 ] 与 [ i+2j-1 , i+2j -1] , 这两个区间的长度都为2j-1,分别求出两个区间最大值,在取较大的那个,就是原区间的最大值。这就是ST算法的动态转移方程。

举例:数列a={ 1 ,4 , 2 , 3 }求f ( 1 , 2 ) =max { f( 1 , 1 ) , f ( 3 , 1 ) }=max { 4 , 3 } = 4 ;
注:初始状态 f ( i , 0 ) = a [i] ;

预处理:

 1 void Init()//nlogn
 2 {
 3     log2[1] = 0;
 4     for(int i = 2; i <= n; i++) log2[i] = log2[i >> 1] + 1; //打log2表
 5     for(int i = 1; i <= n; i++) f[i][0] = a[i]; //建立初始状态
 6     for(int j = 1; (1 << j) <= n; j++)
 7     {
 8         for(int i = 1; i + (1 << j) - 1 <= n; i++)
 9         {
10             f[i][j] = max( f[i][j - 1] , f[i + (1 << j - 1)][j - 1] ); //动态转移方程
11         }
12     }
13 }

查询:

查询区间[a , b ]中最大值,查询的方法比较简单,我们只需要找到一个最大整数 k ,使它满足2k<= b - a +1,例如[ 3 , 11 ] 可以分为 [ 3 , 9 ]
这里我们把待查询的区间分成两个小区间,这两个小区间满足两个条件:(1)这两个小区间要能覆盖整个区间(2)为了利用预处理的结果,要求小区间长度相等。注意两个小区间可能重叠(区间重叠不影响结果)
直接返回 max{ f[a][k] , f[b-(1<<k)+1][k] },于是就求出查询区间中的最大值。

代码如下:

1 int Query(int a, int b)
2 {
3     int k = log2[b - a + 1];
4     return max( f[a][k] , f[b - (1 << k) + 1][k] );
5 }

主程序:

 1 int main()
 2 {
 3     int m, u, v;
 4     cin >> n;
 5     for(int i = 1; i <= n; i++)
 6     {
 7         cin >> arr[i];
 8     }
 9     Init();
10     cin >> m;
11     while(m --)
12     {
13         cin >> u >> v;
14         if(u > v) swap(u, v);
15         cout << Query(u, v) << endl;
16     }
17     return 0;
18 }

综上,ST算法在只有查询的情况下,十分高效,在做了O(nlogn)的预处理后,可以做到O(1)的时间查询。

2016-09-14

(完)

时间: 2024-08-01 22:45:22

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

理解RMQ问题和ST算法的原理

下图为TI C6xx DSP Nyquist总线拓扑图,总线连接了master与slave,提供了高速的数据传输.有很多种速率不同的总线,如图中的红色方框,最高速总线为CPU/2 TeraNet SCR(即VBUSM SCR),带宽为256bit,其他低速总线为CPU/3,CPU/6,带宽参考图中所示.总线之间用Bridge(桥)连接,作用包括转换总线的速率,使之与所流向总线的速率相同等. 在具体应用中,各种速率的总线完全可以满足复杂的数据传输,而数据传输的瓶颈往往在于连接总线之间的Bridge

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 ] 表示从

【RMQ】【ST算法】【模板】士兵杀敌(三)

描述 南将军统率着N个士兵,士兵分别编号为1~N,南将军经常爱拿某一段编号内杀敌数最高的人与杀敌数最低的人进行比较,计算出两个人的杀敌数差值,用这种方法一方面能鼓舞杀敌数高的人,另一方面也算是批评杀敌数低的人,起到了很好的效果. 所以,南将军经常问军师小工第i号士兵到第j号士兵中,杀敌数最高的人与杀敌数最低的人之间军功差值是多少. 现在,请你写一个程序,帮小工回答南将军每次的询问吧. 注意,南将军可能询问很多次. 输入 只有一组测试数据 第一行是两个整数N,Q,其中N表示士兵的总数.Q表示南将军

【动态规划dp】RMQ问题(st算法)

[RMQ] Range Minimum/Maximum Query  范围最值问题 [ST算法] 解决RMQ问题的有效算法 预处理   经过预处理构造出d,预处理时间复杂度 O(nlogn) 运用动态规划的思想   d(i, j) 表示 范围 i ~ i + 2j-1 的最小值则有状态转移方程 d(i, j) = min {      d(i, j-1)       ,    d(i + 2j-1 , j-1)     } 设原数据存储在数组a[]  , 则初始状态 d( i ,  0 ) =

51NOD1174 区间最大数 &amp;&amp; RMQ问题(ST算法)

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

HDU 3183 A Magic Lamp(RMQ问题, ST算法)

原题目 A Magic Lamp Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3964    Accepted Submission(s): 1605 Problem Description Kiki likes traveling. One day she finds a magic lamp, unfortunately the

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

[POJ3264]Balanced Lineup(RMQ, ST算法)

题目链接:http://poj.org/problem?id=3264 典型RMQ,这道题被我鞭尸了三遍也是醉了…这回用新学的st算法. st算法本身是一个区间dp,利用的性质就是相邻两个区间的最值的最值一定是这两个区间合并后的最值,这条性质决定了这个dp子问题的重叠.可以利用这个性质预处理出这张表,只不过步长是2的幂次. 查询的时候也是如此,但是未必会精准地选中两个区间,不要紧,因为两个区间重叠的部分也会被自动算在求最值的内部.这个时候如果算的是区间和的话,要减去这一部分.(区间和的话直接用前

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).但当数据量