【RMQ算法】:用于当数组过于庞大的时候,查询区间的最大(最小)值。
时间复杂度:O(nlogn),主要时间发费在预处理上,查询只要O(1)。
- 描述
-
南将军统率着N个士兵,士兵分别编号为1~N,南将军经常爱拿某一段编号内杀敌数最高的人与杀敌数最低的人进行比较,计算出两个人的杀敌数差值,用这种方法一方面能鼓舞杀敌数高的人,另一方面也算是批评杀敌数低的人,起到了很好的效果。
所以,南将军经常问军师小工第i号士兵到第j号士兵中,杀敌数最高的人与杀敌数最低的人之间军功差值是多少。
现在,请你写一个程序,帮小工回答南将军每次的询问吧。
注意,南将军可能询问很多次。
- 输入
- 只有一组测试数据
第一行是两个整数N,Q,其中N表示士兵的总数。Q表示南将军询问的次数。(1<N<=100000,1<Q<=1000000)
随后的一行有N个整数Vi(0<=Vi<100000000),分别表示每个人的杀敌数。
再之后的Q行,每行有两个正正数m,n,表示南将军询问的是第m号士兵到第n号士兵。 - 输出
- 对于每次询问,输出第m号士兵到第n号士兵之间所有士兵杀敌数的最大值与最小值的差。
- 样例输入
-
5 2 1 2 6 9 3 1 2 2 4
- 样例输出
- 1
- 7
- 代码如下:(数据过大的时候建议用scanf输入,用cin有可能会时间超限)。
#include<cstdio> #include<algorithm> #include<cmath> using namespace std; const int N = 100010; int maxsum[20][N], minsum[20][N]; void RMQ(int num) //预处理->O(nlogn) { for(int i = 1; i != 20; ++i) for(int j = 1; j <= num; ++j) if(j + (1 << i) - 1 <= num) { maxsum[i][j] = max(maxsum[i - 1][j], maxsum[i - 1][j + (1 << i >> 1)]); minsum[i][j] = min(minsum[i - 1][j], minsum[i - 1][j + (1 << i >> 1)]); } } int main() { int num, query; int src, des; scanf("%d %d", &num, &query); for(int i = 1; i <= num; ++i) //输入信息处理 { scanf("%d", &maxsum[0][i]); minsum[0][i] = maxsum[0][i]; } RMQ(num); while(query--) //O(1)查询 { scanf("%d %d", &src, &des); int k = (int)(log(des - src + 1.0) / log(2.0)); int maxres = max(maxsum[k][src], maxsum[k][des - (1 << k) + 1]); int minres = min(minsum[k][src], minsum[k][des - (1 << k) + 1]); printf("%d ", maxres - minres); } return 0; }