RMQ算法
请看一个题
设有一个长度为N的数组arr,求 0<=a<=b<N a~b 的最大值(或最小值) 会求很多次
最简单的算法就是弄一个二维数组,先算好 a~b 的 最大最小值。但是这样太浪费内存了。
RMQ 算法 就是为了巧妙地运用2的幂数/对数 解决这个问题的。
设 dp[i][j] 为 以i为起点,1<<j长度的,最大值。
这样,如果需要求 a~b 的最大值,则只需 求 max(dp[a][某个长度],dp[b-(1<<某个长度)+1][某个长度]
其中 某个长度 = log2(b-a+1)
void query(int a,int b,int &maxV){
int r = mlog2(b-a+1);
maxV = max(dpMax[a][r],dpMax[b-(1<<r)+1][r]);
}
而初始化dp 也是以同样类似的思路去解决。
附 poj3264 ac代码
#include <iostream>
#include <cassert>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <cmath>
#include <climits>
#include <functional>
#include <list>
#include <cstdlib>
#include <set>
#include <stack>
#include <map>
#include <algorithm>
using namespace std;
#define MAXN 50005
int h[MAXN];
int dpMin[MAXN][16];
int dpMax[MAXN][16];
int mlog2(int x) {
double xx = x;
double v1 = log(xx);
double v2 = log(2.0);
return v1/v2;
}
void genDP(int len){
for(int i=0;i<len;i++){
dpMax[i][0] = h[i];
dpMin[i][0] = h[i];
}
for(int j=1;(1<<j)<len;j++){
for( int i=0;i+(1<<j)-1<len;i++ ){
int r = i+(1<<(j-1));
dpMax[i][j] = max(dpMax[i][j-1],dpMax[r][j-1]);
dpMin[i][j] = min(dpMin[i][j-1],dpMin[r][j-1]);
}
}
}
void query(int a,int b,int &maxV,int &minV){
int r = mlog2(b-a+1);
maxV = max(dpMax[a][r],dpMax[b-(1<<r)+1][r]);
minV = min(dpMin[a][r],dpMin[b-(1<<r)+1][r]);
}
int main(){
int N,Q;
int t;
scanf("%d%d",&N,&Q);
for( int i=0;i<N;i++ ){
scanf("%d",&t);
h[i] = t;
}
genDP(N);
int a,b;
int maxV,minV;
for( int i=0;i<Q;i++ ){
scanf("%d%d",&a,&b);
if ( a==b ){
printf("0\n");
}else{
query(a-1,b-1,maxV,minV);
printf("%d\n",maxV-minV);
}
}
return 0;
}