NYOJ 士兵杀敌(三)

描述

南将军统率着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


这题要采用rmq算法(range max/min query)
之前都没听过这个算法,百度了一下:
参考:
http://blog.csdn.net/liang5630/article/details/7917702

RMQ(Range Minimum/Maximum Query),即区间最值查询,是指这样一个问题:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j之间的最小/大值。这两个问题是在实际应用中经常遇到的问题,下面介绍一下解决这两种问题的比较高效的算法。当然,该问题也可以用线段树(也叫区间树)解决,算法复杂度为:O(N)~O(logN),这里我们暂不介绍。

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<math.h>
 4 #define maxvalue(a,b) ((a) > (b)) ? (a) : (b)
 5 #define minvalue(a,b) ((a) < (b)) ? (a) : (b)
 6 int a[100005];
 7 int minsum[100005][20],maxsum[100005][20];
 8 int main()
 9 {
10     int N,Q,m,n,i,j,k;
11     scanf("%d%d",&N,&Q);
12     for (i=1; i <= N; i++){
13         scanf("%d",&a[i]);
14         maxsum[i][0] = a[i];
15         minsum[i][0] = a[i];
16     }
17     for (j=1; j < 20; j++)
18         for(i=1; i <= N; i++)
19     {
20         if(i + ( 1<<j )-1 <= N ){
21             minsum[i][j] = minvalue(minsum[i][j-1],minsum[i+(1<<(j-1))][j-1]);
22             maxsum[i][j] = maxvalue(maxsum[i][j-1],maxsum[i+(1<<(j-1))][j-1]);
23         }
24     }
25     while(Q--){
26         scanf("%d%d",&m,&n);
27         k =log2( n - m + 1);
28         int s = (maxvalue(maxsum[m][k],maxsum[n-(1<<k)+1][k])) - (minvalue(minsum[m][k],minsum[n-(1<<k)+1][k]));
29         printf("%d
",s);
30 
31     }
32 }



原文地址:https://www.cnblogs.com/george-cw/p/3933346.html