RMQ
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=50010;
int maxsum[maxn][20],minsum[maxn][20];
void rmq(int n) //预处理
{
for(int j=1;j<20;j++)
for(int i=1;i<=n;i++)
if(i+(1<<j-1) <= n)
{
maxsum[i][j]=max(maxsum[i][j-1],maxsum[i+(1<<(j-1))][j-1]);
minsum[i][j]=min(minsum[i][j-1],minsum[i+(1<<(j-1))][j-1]);
}
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&maxsum[i][0]);
minsum[i][0]=maxsum[i][0];
}
rmq(n);
int l,r;
while(m--) // 查询
{
scanf("%d%d",&l,&r);
int k=(int)(log(r-l+1.0)/log(2.0));
int ma=max(maxsum[l][k],maxsum[r-(1<<k)+1][k]);
int mi=min(minsum[l][k],minsum[r-(1<<k)+1][k]);
printf("%d\n",ma-mi);
}
return 0;
}
线段树
#include<cstdio>
#include<algorithm>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=524288*2;
int sum[maxn],s[maxn]; //存最值
int node[maxn/2];
void pushup(int rt) //求结点最值
{
sum[rt]=max(sum[rt<<1],sum[rt<<1|1]);
s[rt]=min(s[rt<<1],s[rt<<1|1]);
}
void bulid(int l,int r,int rt) //建树
{
if(l==r)
{
sum[rt]=node[l];
s[rt]=node[l];
return ;
}
int m=(l+r)>>1;
bulid(l,m,rt<<1);
bulid(m+1,r,rt<<1|1);
//更新信息
pushup(rt);
}
// 求 L~R 区间最值
int query(int L,int R,int l,int r,int rt)
{
if(L<=l && r<=R) //在区间内直接返回
return sum[rt];
int m=(l+r)>>1;
//更新最值
int ans=-1;
if(L<=m)
ans=max(ans,query(L,R,l,m,rt<<1));
//左子区间与[L,R]有重叠,递归
if(R>m)
ans=max(ans,query(L,R,m+1,r,rt<<1|1)); //右子区间与[L,R]有重叠,递归
return ans;
}
int query1(int L,int R,int l,int r,int rt)
{
if(L<=l && r<=R) //在区间内直接返回
return s[rt];
int m=(l+r)>>1;
//更新最值
int cnt=inf;
if(L<=m)
cnt=min(cnt,query1(L,R,l,m,rt<<1));
//左子区间与[L,R]有重叠,递归
if(R>m)
cnt=min(cnt,query1(L,R,m+1,r,rt<<1|1)); //右子区间与[L,R]有重叠,递归
return cnt;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&node[i]);
bulid(1,n,1);
while(m--)
{
int x,y;
scanf("%d%d",&x,&y);
if(x==y)
printf("0\n");
else
printf("%d\n",query(x,y,1,n,1)-query1(x,y,1,n,1));
}
return 0;
}