NYOJ 119 士兵殺敵(三)(RMQ演算法),nyojrmq
採用的的是小牛的寫法,蒟蒻第一次寫。。
RMQ (Range Minimum/Maximum Query)問題是指:對於長度為n的數列A,回答若干詢問RMQ(A,i,j)(i,j<=n),返回數列A中下標在i,j裡的最小(大)值,也就是說,RMQ問題是指求區間最值的問題。
這裡介紹ST演算法:採用動態規劃的思想:詳見
士兵殺敵(三)時間限制: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 21 2 6 9 31 22 4
-
範例輸出
-
17
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<limits.h>#include<cmath>typedef long long LL;using namespace std;#define REPF( i , a , b ) for ( int i = a ; i <= b ; ++ i )#define REP( i , n ) for ( int i = 0 ; i < n ; ++ i )#define CLEAR( a , x ) memset ( a , x , sizeof a )const int maxn=100010;int maxsum[maxn][20],minsum[maxn][20];//從第i個起連續2^kint n,m;int l,r;void RMQ(int n){ for(int j=1;j<=20;j++) { for(int i=1;i<=n;i++) { if(i+(1<<j)-1<=n) { maxsum[i][j]=max(maxsum[i][j-1],maxsum[i+(1<<(j-1))][j-1]); minsum[i][j]=min(minsum[i][j-1],minsum[i+(1<<(j-1))][j-1]); } } }}int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&maxsum[i][0]); minsum[i][0]=maxsum[i][0]; } RMQ(n); while(m--) { scanf("%d%d",&l,&r); int k=(int)(log(r-l+1.0)/log(2.0)); int maxres=max(maxsum[l][k],maxsum[r-(1<<k)+1][k]);//注意 int minres=min(minsum[l][k],minsum[r-(1<<k)+1][k]); printf("%d\n",maxres-minres); } return 0;}