应用:
给定一个数列a,
基本的倍增数组可以用O(1)的时间复杂度计算出区间[i,j]的最值。
具体操作:
维护倍增数组
1、状态 dp[j][i]表示区间从i到 i+(2^j)-1,即以i开始长度为2^j 这个区间范围的最值。(下面以最小值为例)
2、状态转移方程:dp[j][i]=min{dp[j-1][i],dp[j-1][i+(1<<(j-1))]};
3、边界值:dp[0][i]=a[i] //以i开始长度为2^0=1
求数组a在区间【i,j】间的最值。
首先计算一个最大的k,使得2^k<=区间长度(j-i+1).
k=log(j-i+1)/log2
则可求得 答案 min(dp[k][i],dp[k][j-(2^k)+1]).
基础题:https://www.luogu.com.cn/problem/P2880
#include<bits/stdc++.h>
using namespace std;
const int N=50005;
int n,q,h[N],mi[21][N],ma[21][N],k,maxn,minn,a,b,x;
int main()
{
scanf("%d%d",&n,&q);
for(int i=1; i<=n; i++){
scanf("%d",&x);
mi[0][i]=ma[0][i]=x;
}
for(int j=1; j<=21; j++)
{
for(int i=1; i+(1<<j)-1<=n; i++){
mi[j][i]=min(mi[j-1][i],mi[j-1][i+(1<<(j-1))]);
ma[j][i]=max(ma[j-1][i],ma[j-1][i+(1<<(j-1))]);
}
}
for(int i=1; i<=q; i++){
scanf("%d%d",&a,&b);
k=(int)(log(b-a+1.0)/log(2.0));
maxn=max(ma[k][a],ma[k][b-(1<<k)+1]);
minn=min(mi[k][a],mi[k][b-(1<<k)+1]);
printf("%d\n",maxn-minn);
}
return 0;
}