POJ 3264 RMQ模版

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


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值