poj 3264 Balanced Lineup
RMQ模板题,用ST算法
//DP预处理 //dp[i][j] 表示从下标i开始,长度为2^j的最大值 //状态转移方程 dp[i][j] = max{ dp[i][j-1] , dp[i+2^(j-1)][j-1] } //也就是一个长度为2^j的区间,二分为两个2^(j-1)的长度 //对于查询[a,b]以内的最大值,先求出区间长度LEN = b-a+1 //查询结果为 res = max{dp[a][k] , dp[b-2^k+1][k]} , 关键是k,是什么,怎么计算 //当满足 2^k >= LEN/2 , 且k最小时,这个k就是我们要的值 //k可以用计算公式一步算得 : k = (int) (log((double)(b-a+1))/log(2.0)) //另外一个问题,对于构建dp值的时候,dp[i][j],这个j最大去到多少? //道理是一样的,对于总区间,长度为L,同样是 2^j >= L/2 , 取最小的j就是我们要的值 //所以也可以用公式一步计算出来 j = (int) (log((double)L) / log(2.0)) #include <iostream> #include <cstdio> #include <cstring> #include <cmath> using namespace std; #define N 50010 #define M 20 int n,m,a[N],dp[N][M],__dp[N][M]; void TEST() { cout << "最大值" << endl; int K = (int) (log((double)n) / log(2.0)); for(int i=1; i<=n; i++) for(int j=0; j<=K; j++) printf("dp[%d,%d] = %d\n",i,j,dp[i][j]); cout << "最小值" << endl; for(int i=1; i<=n; i++) for(int j=0; j<=K; j++) printf("__dp[%d,%d] = %d\n",i,j,__dp[i][j]); } void ST() { for(int i=1; i<=n; i++) dp[i][0] = __dp[i][0] = a[i]; int K = (int) (log((double)n) / log(2.0)); for(int j=1; j<=K; j++) for(int i=1; i+(1<<j)-1 <= n; i++) { int k = i+(1<<(j-1)); dp[i][j] = max( dp[i][j-1] , dp[k][j-1] ); __dp[i][j] = min( __dp[i][j-1] , __dp[k][j-1]); } } int RMQ(int x ,int y) { int K = (int) (log((double)(y-x+1)) / log(2.0)); int k = y-(1<<K)+1; int Max = max( dp[x][K] , dp[k][K]); int Min = min( __dp[x][K] , __dp[k][K]); return Max - Min; } int main() { while(cin >> n >> m) { for(int i=1; i<=n ;i++) cin >> a[i]; ST(); //TEST(); while(m--) { int x,y; cin >> x >> y; int res = RMQ(x,y); cout << res << endl; } } return 0; }