rmq范圍最小(大)指問題——處理對于n個數,要求快速求出某區間內的最值。
f[i][j]表示以i為起點長度為2^j的最值。
f[i][j] = rmq(f[i][j-1], f[i + 2 ^ (j-1)][j-1];相當于把線段分成相等的左右兩段合并求rmq。但這得讓線段長度是2的冪次。
查詢時,例如f[1,7] = f[1][2] + f[5][1] + f[7][0];為O(logn),f[1, 7]對應于數組中的區間
為了加快查詢,可使f[1,7] = f[1][2] + f[4][2];為O(1),這里用2=(2^k <= 7)k的最大值7 - 2^2 + 1 為4,即讓7向左移動2^2 - 1個位,2^k = 1 << k;注意:例如給出n=7,則f[4][2]是求對應于[4, 8]的rmq,而f[4, 8] = f[4, 7],所以要對此進行預處理,讓右區間的值超過n的為右區間為n時的值,這樣才能加快查詢,即多增加了一些方便查詢的數據。最大左移是k = log2(n),可表示的最大起始點是1 << k,則f[i][j]表示的右區間的最大值為
(1 << k) + (1 << k) = 1 << (k + 1) = 2 ^ (log2(n) + 1),提供這個數據時能給出何時得空間[n + 1][log2(n) + 1 + 1]。
代碼:

#include  < stdio.h >
#include 
< stdlib.h >
#include 
< math.h >
#define  maxn 50010
#define  Min(a, b) a < b ? a : b
#define  Max(a, b) a > b ? a : b
struct  t
{
    
int  min, max;
}map[maxn][
20 ];
void  build ( int  n)
{
    
int  i, j, m, r  =  n, c  =  log(( double )n)  /  log( 2.0 );
    
for  (i  =   1 ; i  <=  c; i ++ )
    {
        
for  (j  =   1 ; j  <=  r; j ++ )
        {
            m 
=  j  +  ( 1   <<  (i  -   1 )); // 右半部分的起始值
             if  (m  <=  r)
            {
                map[j][i].min 
=  Min(map[j][i - 1 ].min ,map[m][i - 1 ].min);
                map[j][i].max 
=  Max(map[j][i - 1 ].max, map[m][i - 1 ].max);
            }
            
else // 長度超出n的,就當是j起點的最后一個終點的rmq。實現這步能使查詢為O(1).
            {
                map[j][i].min 
=  map[j][i - 1 ].min;
                map[j][i].max 
=  map[j][i - 1 ].max;
            }
        }
    }
}
int  query( int  l,  int  r)
{
    
int  len  =  r  -  l  +   1 ;
    
int  k  =  log(( double )len)  /  log( 2.0 );
    
int  m  =  r  -  ( 1   <<  k)  +   1 ;
    
int  min  =  Min(map[l][k].min, map[m][k].min);
    
int  max  =  Max(map[l][k].max, map[m][k].max);
    
return  max  -  min;
}
int  main()
{
    
int  n, m,  i, l, r;
    scanf(
" %d%d " & n,  & m);
    
for  (i  =   1 ; i  <=  n; i ++ )
    {
        scanf(
" %d " & map[i][ 0 ].min);
        map[i][
0 ].max  =  map[i][ 0 ].min;
    }
    build (n);
    
while  (m -- )
    {
        scanf(
" %d%d " & l,  & r);
        printf(
" %d\n " , query(l, r));
    }
    
return   0 ;
}