码迷,mamicode.com
首页 > 其他好文 > 详细

RMQ

时间:2017-11-09 22:49:53      阅读:429      评论:0      收藏:0      [点我收藏+]

标签:预处理   double   处理   需要   pre   表示   最大   之间   数列   

解决RMQ(Range Minimum/Maximum Query)即区间最大最小值问题。

有一个离线算法(ST算法),这个算法是很高效了,时间是O(nlogn):(用O(nlogn)的时间进行预处理,再用O(1)的时间进行区间查询)

1.先是预处理(用动态规划解决)

 A数列为:3 2 4 5 6 8 1 2 9 7

F[1,0]表示第1个数起,长度为2^0=1的最大值,其实就是3这个数。同理 F[1,1] = max(3,2) = 3, F[1,2]=max(3,2,4,5) = 5,F[1,3] = max(3,2,4,5,6,8,1,2) = 8;

首先,DP的初始值,即第一次时,每次都是自己本身:F[i,0] = A[i]。

然后是动态转移方程 F[ i ][ j ] = max ( F[ i ] [ j-1 ], F[ i + 2^( j - 1 ) ] [ j - 1 ]);

代码:

 1 void RMQ(int num) //预处理->O(nlogn)  
 2 {
 3     //初始化
 4     for (int i = 1; i <= num; i++){
 5         minsum[i][0] = a[i];
 6         maxsum[i][0] = a[i];
 7     }
 8 
 9     for (int j = 1; j < 25; j++)
10     for (int i = 1; i <= num; i++)
11     if (i + (1 << j) - 1 <= num)
12     {
13         maxsum[i][j] = max(maxsum[i][j - 1], maxsum[i + (1 << (j - 1))][j - 1]);
14         minsum[i][j] = min(minsum[i][j - 1], minsum[i + (1 << (j - 1))][j - 1]);
15     }
16 }

其中 i 和 j 的位置不能变,因为是先更新 1 个元素,再更新两个,四个.....等元素,以此类推更新所有长度的最值。

2.查询

 1 //查询
 2 int getmin(int x, int y){
 3     int k = (int)(log((double)(y - x + 1)) / log(2.0));
 4     return min(minsum[x][k], minsum[y - (1 << k) + 1][k]);
 5 }
 6 
 7 int getmax(int x, int y){
 8     int k = (int)(log((double)(y - x + 1)) / log(2.0));
 9     return max(maxsum[x][k], maxsum[y - (1 << k) + 1][k]);
10 }

对于需要查询的区间[ x, y],区间的差值为 len = y - x + 1;

那么查询的时候 设此时的 j 是 k,那么在查询时,需要 x -- x + 2^k -1 和 y - 2^k + 1 -- y之间,此时就要找到合适的K值。

1 int k=0;  
2     while((1<<(k+1))<=y-x+1)  
3         k++;  

用这个方法找也可以,不过有个更快捷的 k=log2( y - x + 1) 直接进行取值。

RMQ

标签:预处理   double   处理   需要   pre   表示   最大   之间   数列   

原文地址:http://www.cnblogs.com/jaydenouyang/p/7811230.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!