1. 程式人生 > >Balanced Lineup POJ - 3264(RMQ)

Balanced Lineup POJ - 3264(RMQ)

Balanced Lineup POJ - 3264

題目連線

題意:給出一個數列,Q個詢問,問區間[A, B]中最大值與最小值的差;
思路:線段樹可以做,維護最大最小值,直接查詢就可以;但是現在要用RMQ做;
何為RMQ?(Range Minimum/Maximum Query) 區間最值詢問,通過O(nlogn)的預處理可以在O(1)的時間內找到區間的最值;下面以最大值為例:
令Fmax[i][j]表示區間[i, i+2^j]中的最大值;那麼F[i][j]=max(F[i][j-1], F[i+2^(j-1)][j-1]);

init(){
    for(int
j=1; (1<<j)<=n; j++){ for(int i=1; i+(1<<j)-1<=n; i++){ Fmax[i][j]=max(Fmax[i][j-1], Fmax[i+(1<<(j-1))][j-1]); } } }

對於區間[A, B]內的詢問有:

int k=(int)(log(B-A+1.0)/log(2.0));
query(A, B)=max(Fmax[A][k], Fmax[B-(1<<k)+1][k]);

本題程式碼:

#include <stdio.h>
#include <algorithm> #include <string.h> #include <math.h> using namespace std; const int maxn=5e4+10; int Fmax[maxn][20], Fmin[maxn][20], n, Q; void init(){ for(int i=1; (1<<i)<=n; i++){ for(int j=1; j+(1<<i)-1<=n; j++){ Fmax[j][i]=max(Fmax[j][i-1
], Fmax[j+(1<<(i-1))][i-1]); Fmin[j][i]=min(Fmin[j][i-1], Fmin[j+(1<<(i-1))][i-1]); } } } int main(){ while(~scanf("%d%d", &n, &Q)){ for(int i=1; i<=n; i++){ scanf("%d", &Fmax[i][0]); Fmin[i][0]=Fmax[i][0]; } init(); while(Q--){ int x, y; scanf("%d%d", &x, &y); int k=(int)(log(y-x+1.0)/log(2.0)); printf("%d\n", max(Fmax[x][k], Fmax[y-(1<<k)+1][k])-min(Fmin[x][k], Fmin[y-(1<<k)+1][k])); } } return 0; }