显然是RMQ问题
用ST表就行了
用倍增的思想,像DP一样转移
设 mx[ i ] [ j ] 表示从点 i 开始,后面一共 2^j 个点的最大值
显然 mx[ i ] [ 0 ] = a [ i ](a是原数列)
那么 mx [ i ] [ j ] = max( mx[ i ] [ j-1 ],mx[ i+( 1<<(j-1) ) ] [ j-1 ] ) (前面半段和后面半段取个最值)
预处理是 O(nlogn) 的
for(int i=1;i<=n;i++) mx[i][0]=a[i];//初始值 for(int i=1;(1<<i)<=n;i++) for(int j=1;j<=n;j++) mx[j][i]=max(mx[j][i-1],mx[j+(1<<(i-1))][i-1]);//更新
询问是 O(1) 的
找到前面一段区间和后面一段区间(中间有重复覆盖没关系,只要能覆盖到所有点就行)
这样就可以保证覆盖到所有的点了
inline void query(int l,int r) { int k=Log[r-l+1]; printf("%d ", max(mx[l][k],mx[r-(1<<k)+1][k])-min(mi[l][k],mi[r-(1<<k)+1][k]) ); }
最小值也差不多,就不仔细讲了
最后是完整代码
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<cmath> using namespace std; const int N=1e5+7; int n,m; int Log[N]; inline void pre_log()//预处理log { Log[1]=0; for(int i=2;i<=n;i++) Log[i]=Log[i>>1]+1; } int a[N]; int mx[N][27],mi[N][27]; inline void query(int l,int r)//询问 { int k=Log[r-l+1]; printf("%d ", max(mx[l][k],mx[r-(1<<k)+1][k])-min(mi[l][k],mi[r-(1<<k)+1][k]) ); } int main() { int l,r; cin>>n>>m; pre_log(); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) mx[i][0]=mi[i][0]=a[i];//初始值 for(int i=1;(1<<i)<=n;i++) for(int j=1;j<=n;j++) { mx[j][i]=max(mx[j][i-1],mx[j+(1<<(i-1))][i-1]); mi[j][i]=min(mi[j][i-1],mi[j+(1<<(i-1))][i-1]); } while(m--) { scanf("%d%d",&l,&r); query(l,r); } return 0; }