POJ 3264 Balanced Lineup RMQ ST算法

题意:有n头牛,编号从1到n,每头牛的身高已知。现有q次询问,每次询问给出a,b两个数。要求给出编号在a与b之间牛身高的最大值与最小值之差。

思路:标准的RMQ问题。

RMQ问题是求给定区间内的最值问题。当询问量巨大时,最朴素算法必然超时。解决RMQ比较优秀的算法有ST算法。其预处理时间复杂度为O(nlogn),询问的时间复杂度为O(1)。

ST的思想如下:

假设num数组中的数据从第0位开始存储。

用两个二维数组tmax,tmin分别求区间最大与最小值。ST的关键是数组区间的分割。tmax和tmin的下标是一致的,暂且拿tmax举例。

预处理:

预处理阶段运用的是DP的思想。tmax[i][j]内的值为区间[i, i + 2^j - 1]内的最大值。可以方便地理解为:第一个下标i为区间的开始位置,第二个坐标j表示区间的长度(只不过长度为指数形式)。如tmax[2][1]表示的是区间[2, 3]的最大值,tmax[2][2]表示的是区间[2, 5]的最大值。

而区间[i, i + 2^j - 1]可拆成[i, i + 2^(j - 1) - 1]和[i + 2^(j - 1), i + 2^j - 1]两个子区间。因此要计算tmax[i][j]的值,则有tmax[i][j] = max(tmax[i][j-1], tmax[i+2^(j-1)][j-1])。而所有递推的最初值tmax[i][0] = num[i]。对于tmin数组,下标的表示规则是相同的。

查询:

预处理进行完之后,可以进行查询。查询的复杂度为O(1)。

假设要查询区间[i, j]内的最大值。

首先第一步,先计算出一个整数k,k为满足表达式i + 2^k - 1 <= j 的最大整数。

然后将区间[i, j]分成两个部分重叠的子区间:[i, i + 2^k - 1]与[j - 2^k + 1, j]。

而tmax[i][k] 与tmax[j-2^k+1][k]中在预处理阶段便已计算出了结果,此时只需要输出两者中的较大者即可。

其他细节请看代码。

 

 1 #include<stdio.h>
 2 #include<math.h>
 3 #include<algorithm>
 4 #define maxn 50020
 5 using namespace std;
 6 
 7 int cow[maxn], tmax[maxn][33], tmin[maxn][33];
 8 void st(int n)
 9 {
10     int k = (int)(log((double)n) / log(2.0));
11     for (int i = 0; i < n; i++)
12         tmin[i][0] = tmax[i][0] = cow[i];//递推的初值
13     for (int j = 1; j <= k; j++)
14         for (int i = 0; i + (1 << j) - 1 < n; i++)
15         {
16             int m = i + (1 << (j - 1));//求出中间值
17             tmax[i][j] = max(tmax[i][j-1], tmax[m][j-1]);
18             tmin[i][j] = min(tmin[i][j-1], tmin[m][j-1]);
19         }
20 }
21 //查询i和j之间的最值,注意i是从0开始的
22 void rmq(int i, int j)
23 {
24     int k = (int)(log(double(j - i + 1)) / log(2.0));
25     int t1 = max(tmax[i][k], tmax[j-(1<<k)+1][k]);
26     int t2 = min(tmin[i][k], tmin[j-(1<<k)+1][k]);
27     printf("%d\n",t1 - t2);
28 }
29 int main()
30 {
31     int n, q;
32     //freopen("data.in", "r", stdin);
33     scanf("%d%d",&n,&q);
34     for (int i = 0; i < n; i++) scanf("%d",&cow[i]);
35     st(n);
36     while (q--)
37     {
38         int a, b;
39         scanf("%d%d",&a,&b);
40         rmq(a - 1, b - 1);//st算法从第0位开始,因此需要减一
41     }
42     return 0;
43 }

 

 

 

posted @ 2013-07-29 11:11  fenshen371  阅读(237)  评论(0编辑  收藏  举报