写RMQ练练手。
这道题差一点刷进第一版,明天再优化一下。
RMQ[i][j],表示从i开始后面的 2 ^ j 个数中,他的最大(最小)值。
预处理的时候,我们将每个需要处理的区间分成两部分,[i , i + (2 ^ (j - 1))] , [i + (2 ^ (j - 1)) , i + 2 ^ j] 。
那么整个区间的最大(最小)值就是两个区间的最大最小值。
对于临界状态,我们可以知道RMQ[i][0] = a[i] 。
那么我们可以使用动态规划的方法来预处理,转移方程就是RMQ[i][j] = max(RMQ[i][j - 1] , RMQ[i + (1 << (j - 1))][j - 1]) 。
#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <vector>
#include <iomanip>
#include <cstring>
#include <iostream>
#include <algorithm>
#define Max 2505
#define FI first
#define SE second
#define ll long long
#define PI acos(-1.0)
#define inf 0x3fffffff
#define LL(x) ( x << 1 )
#define bug puts("here")
#define PII pair<int,int>
#define RR(x) ( x << 1 | 1 )
#define mp(a,b) make_pair(a,b)
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,s,t) for( int i = ( s ) ; i <= ( t ) ; ++ i )
using namespace std;
inline void RD(int &ret) {
char c;
int flag = 1 ;
do {
c = getchar();
if(c == '-')flag = -1 ;
} while(c < '0' || c > '9') ;
ret = c - '0';
while((c=getchar()) >= '0' && c <= '9')
ret = ret * 10 + ( c - '0' );
ret *= flag ;
}
inline void OT(int a) {
if(a >= 10)OT(a / 10) ;
putchar(a % 10 + '0') ;
}
#define N 50005
int LOG[N] ;
int n , m ;
int RMQ_MAX[N][20] ,RMQ_MIN[N][20] ;
int a[N] ;
inline int max(int a ,int b){
return a > b ? a : b ;
}
inline int min(int a ,int b){
return a < b ? a : b ;
}
void init(){
for (int i = 1 ; i <= n ; i ++ ){
RMQ_MAX[i][0] = RMQ_MIN[i][0] = a[i] ;
}
for (int i = 1 ; i <= LOG[n] ; i ++ ){
for (int j = 1 ; j <= n + 1 - (1 << i); j ++ ){
RMQ_MAX[j][i] = max(RMQ_MAX[j][i - 1] ,RMQ_MAX[j + (1 << (i - 1))][i - 1] ) ;
RMQ_MIN[j][i] = min(RMQ_MIN[j][i - 1] ,RMQ_MIN[j + (1 << (i - 1))][i - 1] ) ;
}
}
}
int RMQ(int l, int r){
int k = LOG[r - l + 1] ;
int MAX = max(RMQ_MAX[l][k] , RMQ_MAX[r - (1 << k) + 1][k]) ;
int MIN = min(RMQ_MIN[l][k] , RMQ_MIN[r - (1 << k) + 1][k]) ;
return MAX - MIN ;
}
int main() {
LOG[0] = -1 ;
for (int i = 1 ; i < N ; i ++ ){
LOG[i] = ((i & (i - 1)) == 0) ? LOG[i - 1] + 1 : LOG[i - 1] ;
}
while(scanf("%d%d",&n,&m) == 2){
for (int i = 1 ; i <= n ; i ++ )RD(a[i]) ;
init() ;
int c , d ;
while(m -- ){
RD(c) ; RD(d) ;
OT(RMQ(c , d)) ;putchar('\n') ;
}
}
return 0 ;
}