写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 ; }