士兵杀敌(三)
时间限制:2000 ms | 内存限制:65535 KB
难度:5
- 描述
-
南将军统率着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算法,感觉挺复杂,也没看。。。还有宏定义最好大写。。。。。
思路:线段树叶子节点存两个值:最大和最小值#include <iostream> #include <iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> #include <stdio.h> #include <string.h> #define rep(i , n) for(int i = 0 ; i < (n) ; i++) using namespace std; const int N = 100009 ; const int INF=0x3f3f3f3f; long long ans = 0 , flag = 1; long long a[200009] , sum1[200009] , sum2[200009]; long long max1 = -INF , min1 = INF; struct Node{ long long l , r , mi , ma ; }tree[N*4]; void build(long long l , long long r , int root) { tree[root].l = l , tree[root].r = r ; if(l == r) { scanf("%lld" ,&tree[root].mi); tree[root].ma = tree[root].mi ; return ; } long long mid = (l + r) >> 1; if(l <= mid) build(l , mid , root*2); if(r > mid) build(mid+1 , r , root*2+1); tree[root].mi = min(tree[root*2].mi , tree[root*2+1].mi); tree[root].ma = max(tree[root*2].ma , tree[root*2+1].ma); cout << tree[root].ma << " " << tree[root].mi << endl ; } void query(long long l , long long r , int root) { if(tree[root].l >= l && tree[root].r <= r) { cout << tree[root].ma <<" " << tree[root].mi <<endl ; max1 = max(max1 , tree[root].ma) ; min1 = min(min1 , tree[root].mi) ; return ; } long long mid = (tree[root].l + tree[root].r) >> 1 ; if(l <= mid) query(l , r , root*2); if(r > mid) query(l , r, root*2+1); } int main() { int n , q ; while(~scanf("%d%d" , &n , &q)) { build(1 , n , 1); for(int i = 0 ; i < q ; i++) { long long l , r ; scanf("%lld%lld" , &l ,&r); query(l , r , 1); cout << max1 - min1 << endl ; max1 = -INF , min1 = INF ; // 不能赋值为零噢。 } } return 0; }
RMQ(算法)st表排序
https://blog.csdn.net/niushuai666/article/details/6624672
#include <iostream> #include <iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> #include <stdio.h> #include <math.h> #include <string.h> #define rep(i , n) for(int i = 0 ; i < (n) ; i++) using namespace std; const int N = 10009 ; const int INF=0x3f3f3f3f; long long ans = 0 , flag = 1; long long max1 = -INF , min1 = INF; int a[N] , dpa[N][N] , dpb[N][N]; int n , q ;
void RMQ() { for(int j = 1 ; j < 20 ; j++) { for(int i = 1 ; i <= n ; i++) { if(i + (1 << j) - 1 <= n) { dpa[i][j] = max(dpa[i][j-1] , dpa[i + (1 << j - 1)][j-1]);//状态转移方程 dpb[i][j] = min(dpb[i][j-1] , dpb[i+ (1 << j - 1)][j-1]); } } } } int main() { while(~scanf("%d%d" , &n , &q)) { for(int i = 1 ; i <= n ; i++) { scanf("%d" , &a[i]); dpa[i][0] = dpb[i][0] = a[i];//赋初值 } RMQ(); for(int i = 0 ; i < q ; i++) { long long l , r ; scanf("%lld%lld" , &l ,&r); int k = (int)(log(r - l + 1) / log(2.0)) ; int max1 = max(dpa[l][k] , dpa[r-(1 << k) + 1][k]);//查表 int min1 = min(dpb[l][k] , dpb[r -(1 << k) + 1][k]); printf("%d " , max1 - min1); } } return 0; }