POJ 3264 Balanced Lineup (区间最值问题)

 

Description

For the daily milking, Farmer John's N cows (1 ≤ N ≤ 50,000) always line up in the same order. One day Farmer John decides to organize a game of Ultimate Frisbee with some of the cows. To keep things simple, he will take a contiguous range of cows from the milking lineup to play the game. However, for all the cows to have fun they should not differ too much in height.

Farmer John has made a list of Q (1 ≤ Q ≤ 200,000) potential groups of cows and their heights (1 ≤ height ≤ 1,000,000). For each group, he wants your help to determine the difference in height between the shortest and the tallest cow in the group.

Input

Line 1: Two space-separated integers, N and Q
Lines 2..N+1: Line i+1 contains a single integer that is the height of cow i 
Lines N+2..N+Q+1: Two integers A and B (1 ≤ A ≤ B ≤ N), representing the range of cows from A to B inclusive.

Output

Lines 1..Q: Each line contains a single integer that is a response to a reply and indicates the difference in height between the tallest and shortest cow in the range.

Sample Input

6 3
1
7
3
4
2
5
1 5
4 6
2 2

Sample Output

6
3
0


思路:题目意思是查询给定区间最大值与最小值的差值,是一个典型的ST算法,RMQ区间最值查询问题。
给定一个长度为N的数列 ST算法能在 O(NlogN)时间的预处理后,o(1)查询指定区间最值。



 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<map>
 7 #include<set>
 8 #include<vector>
 9 #include<queue>
10 #include<list>
11 //#include<unordered_map>
12 #include<stack>
13 using namespace std;
14 #define ll long long 
15 const int mod=1e9+7;
16 const int inf=1e9+7;
17 
18 const int maxn=1e5+5;
19 
20 int num[maxn];
21 
22 int f_max[maxn][30];
23 int f_min[maxn][30];
24 
25 int n,op;
26 
27 //设f[i][j]表示数列中下标在子区间[i,i+2^j -1]里的数的最值。
28 //也就是从i开始的2^j个数的最值。
29 //递推边界显然是f[i][0]=num[i]
30 //即数列在子区间[i,i]里的最大值 
31 
32 void ST_prework()
33 {
34     for(int i=1;i<=n;i++)
35     {
36         f_max[i][0]=num[i];
37         f_min[i][0]=num[i];
38     }
39     int t=log2(n)+1;
40     for(int j=1;j<t;j++)
41     {
42         for(int i=1;i<=n-(1<<j)+1;i++)
43         {   //在递推时,我们把子区间的长度成倍增长 
44             f_max[i][j]=max(f_max[i][j-1],f_max[i+(1<<(j-1))][j-1]);
45             f_min[i][j]=min(f_min[i][j-1],f_min[i+(1<<(j-1))][j-1]);
46             //即长度为2^j的子区间的最值是左右两半长度为2^(j-1)的子区间的最值中较大或较小的一个 
47         }
48     }
49 
50  } 
51  
52 //在询问任意区间[left,right]的最值时,我们先计算一个k值,
53 //满足2^k<right-left+1<=2^(k+1)
54 //也就是使2的k次幂小于区间长度的前提下的最大的k
55 //那么"从left开始的2^k个数"和"以right结尾的2的^k个数"
56 //这两段一定覆盖了整个区间 
57  
58 int ST_query(int left,int right)
59 {
60     int k=log2(right-left+1);
61     return  max(f_max[left][k],f_max[right-(1<<k)+1][k]) - min(f_min[left][k],f_min[right-(1<<k)+1][k]) ;
62 }
63 
64 
65 int main()
66 {
67 //    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
68     
69     scanf("%d%d",&n,&op);
70     
71     for(int i=1;i<=n;i++)
72         scanf("%d",&num[i]);
73         
74     ST_prework();
75     
76     int left,right;
77     
78     for(int i=0;i<op;i++)
79     {
80         scanf("%d%d",&left,&right);
81         
82         printf("%d\n",ST_query(left,right));
83     }
84     
85     return 0;
86 }


猜你喜欢

转载自www.cnblogs.com/xwl3109377858/p/11330647.html