士兵杀敌(三)(RMQ)(DP) or ( 线段树 )
士兵杀敌(三)
时间限制: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在我学习之后我觉得很像分制,你可以体会一下,把区间分成两份
-
然后 get_max OR get_min 希望对后来者有帮助
-
AC 代码(RMQ):
-
#include<bits/stdc++.h> using namespace std; const int maxn = 100000 + 5; int a[maxn]; int mn[maxn][25],mx[maxn][25]; int n,q,l,r; struct RMQ{ int log2[maxn]; void init(){ for(int i = 0; i <= n; i ++)log2[i] = (i == 0 ? -1 : log2[i >> 1] + 1); for(int j = 1; j < 20; j ++) for(int i = 1; i + (1 << j) <= n + 1; i ++) { mn[i][j] = min(mn[i][j - 1], mn[i + (1 << j - 1)][j - 1]); mx[i][j] = max(mx[i][j - 1], mx[i + (1 << j - 1)][j - 1]); } } int querymx(int ql, int qr){ int k = log2[qr - ql + 1]; return max(mx[ql][k], mx[qr - (1 << k) + 1][k]); } int querymn(int ql, int qr){ int k = log2[qr - ql + 1]; return min(mn[ql][k], mn[qr - (1 << k) + 1][k]); } }rmq; void slove(){ rmq.init(); while(q --){ scanf("%d%d", &l, &r); printf("%d\n", rmq.querymx(l, r) - rmq.querymn(l, r)); } } int main(){ while(~scanf("%d %d", &n,&q)){ for(int i = 1; i <= n; i ++){ scanf("%d",&a[i]); mn[i][0] = a[i]; mx[i][0] = a[i]; } slove(); } return 0; }
AC 代码:(线段树)
-
线段树其实也是分治的一种,可以好好学习一下
-
#include <bits/stdc++.h> using namespace std; const int maxn = 100005; #define INF 0x3f3f3f3f struct segeTree{ int l,r,v1,v2;//v1 min ** v2 max }ss[maxn<<2]; void Build(int l,int r,int k) { ss[k].l = l;ss[k].r = r; if(l == r){ scanf("%d",&ss[k].v2); ss[k].v1 = ss[k].v2; //printf("ss[%d].v1.v2 = %d\n",k,ss[k].v1); return; } int mid = (l + r)/2; Build(l, mid , k * 2); Build(mid + 1 ,r , k * 2 + 1); ss[k].v1 = ss[k * 2].v1 > ss[k * 2 + 1].v1 ? ss[k * 2 + 1].v1 : ss[k * 2].v1; ss[k].v2 = ss[k * 2].v2 > ss[k * 2 + 1].v2 ? ss[k * 2].v2 : ss[k * 2 + 1].v2; } int maxx,minn; void query(int x,int y,int l,int r,int k) { if(l == x && r == y){ //printf("maxx = %d ss[%d].v2 = %d\n",maxx,k,ss[k].v2); //printf("minn = %d ss[%d].v1 = %d\n",minn,k,ss[k].v1); maxx = max(maxx,ss[k].v2); minn = min(minn,ss[k].v1); return; } int mid = ( l + r ) >> 1; if(mid >= y) query(x ,y ,l ,mid ,k * 2 ); else if (mid < x) query(x ,y ,mid + 1 ,r ,k * 2 + 1 ); else { query(x ,mid ,l ,mid ,k*2 ); query(mid + 1 ,y ,mid + 1 ,r ,k * 2 + 1 ); } } int main() { int n,m,a,b; scanf("%d %d",&n,&m); Build(1 ,n ,1 ); while( m-- ) { maxx = -1*INF; minn = INF; scanf("%d %d",&a,&b); query(a ,b ,1 ,n ,1 ); printf("%d\n",maxx - minn); } return 0; }
-