士兵杀敌(三)
时间限制: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算法,RMQ比较省时间,相对较优秀, - 其实线段树也是比较常规的方法;
- 代码如下:线段树
-
View Code
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int maxx=100010; 7 int a[maxx]; 8 int big,small; 9 struct node 10 { 11 int left,right; 12 int Max,Min; 13 }tree[3*maxx]; 14 void build(int l,int r,int v) 15 { 16 tree[v].left=l; 17 tree[v].right=r; 18 if(l==r) 19 { 20 tree[v].Max=a[l]; 21 tree[v].Min=a[l]; 22 return ; 23 } 24 int mid=(l+r)>>1; 25 build(l,mid,v*2); 26 build(mid+1,r,v*2+1); 27 tree[v].Max=max(tree[2*v].Max,tree[2*v+1].Max); 28 tree[v].Min=min(tree[2*v].Min,tree[2*v+1].Min); 29 } 30 void query(int a,int b,int v) 31 { 32 if(tree[v].left==a && tree[v].right==b) 33 { 34 if(tree[v].Max>big) big=tree[v].Max; 35 if(tree[v].Min<small) small=tree[v].Min; 36 return ; 37 } 38 int mid=(tree[v].left+tree[v].right)>>1; 39 if(b<=mid) query(a,b,2*v); 40 else if(a>mid) query(a,b,2*v+1); 41 else 42 { 43 query(a,mid,v*2); 44 query(mid+1,b,v*2+1); 45 } 46 } 47 int main() 48 { 49 int n,m,q,l,r,i; 50 scanf("%d%d",&n,&q); 51 for(i=1;i<=n;i++) 52 scanf("%d",&a[i]); 53 build(1,n,1); 54 for(i=0;i<q;i++) 55 { 56 scanf("%d%d",&l,&r); 57 big=-1,small=100000005; 58 query(l,r,1); 59 printf("%d\n",big-small); 60 } 61 return 0; 62 }