这是一道RMQ 题目。
关键是求RMQ
dpmax[i][j] 表示从第i个数字起 2^j 长度范围的的最大值。
则 dp[ i] [0] 表示第i个数字本身
void rmq(int n)
{
for(int j=1;j<=log2(n);j++) //注意取等号。
{
for(int i=0;i<n;i++)
{
if(i+pw[j-1]>=n)
continue;
dpmax[i][j]=max(dpmax[i][j-1],dpmax[i+pw[j-1]][j-1]);
dpmin[i][j]=min(dpmin[i][j-1],dpmin[i+pw[j-1]][j-1]);
}
}
}
这里我们需要注意的是循环的顺序,我们发现外层是j,内层所i。
在查询的时候,因为这个区间的长度为b - a + 1,所以我们可以取k=log2( b - a + 1),则有:RMQ(A, i, j)=max{F[i , k], F[ j - 2 ^ k + 1, k]}。
AC 代码 1766ms
#include <iostream>
#include <stdio.h>
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
using namespace std;
const int N=50010;
int p[N],pw[N];
int dpmax[N][20],dpmin[N][20];
int log2(int n) // 求log2(n)
{
int cnt=0;
while(n)
{
n>>=1;
cnt++;
}
return --cnt;
}
void rmq(int n)
{
for(int j=1;j<=log2(n);j++)
{
for(int i=0;i<n;i++)
{
if(i+pw[j-1]>=n)
continue;
dpmax[i][j]=max(dpmax[i][j-1],dpmax[i+pw[j-1]][j-1]); //多个方框的时候要注意有没有漏掉,经常在这里出错误
dpmin[i][j]=min(dpmin[i][j-1],dpmin[i+pw[j-1]][j-1]);
}
}
}
int main()
{
int n,q,i,j;
pw[0]=1; //初始化为1;
for(i=1;i<=20;i++)
pw[i]=pw[i-1]*2;
while(cin>>n>>q)
{
for(i=0;i<n;i++)
{
scanf("%d",&p[i]);
dpmax[i][0]=p[i];
dpmin[i][0]=p[i];
}
rmq(n);
for(i=0;i<q;i++)
{
int a,b;
scanf("%d%d",&a,&b);
a--,b--; //注意这里要自减,因为数组的范围是0~n-1,否则会越界或其他错误。
j=log2(b-a+1);
int mx=max(dpmax[a][j],dpmax[b-pw[j]+1][j]);
int mm=min(dpmin[a][j],dpmin[b-pw[j]+1][j]);
cout<<mx-mm<<endl;
}
}
}
线段树做法 1547ms
#include <stdio.h>
#include <algorithm>
#include <memory.h>
#define max(a,b) ( (a)>(b)?(a):(b) )
#define min(a,b) ( (a)<(b)?(a):(b) )
#define N 50005
#define INF 1e8;
int M;
int Max[N<<2];
int Min[N<<2];
int Max_ans,Min_ans;
void build(int l,int r,int rt)
{
if(l==r)
{
scanf("%d",&Max[rt]);
Min[rt]=Max[rt];
return;
}
int m=(l+r)>>1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
Min[rt]=min(Min[rt<<1],Min[rt<<1|1]);
Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);
}
void query(int l,int r,int rt,int L,int R)
{
if(L<=l&&R>=r)
{
Max_ans=max(Max_ans,Max[rt]);
Min_ans=min(Min_ans,Min[rt]);
return ;
}
int m=(l+r)>>1;
if(L<=m)
query(l,m,rt<<1,L,R);
if(R>m)
query(m+1,r,rt<<1|1,L,R);
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
build(1,n,1);
while(m--)
{
int a,b;
scanf("%d%d",&a,&b);
Max_ans=-1e8;
Min_ans=1e8;
query(1,n,1,a,b);
printf("%d\n",Max_ans-Min_ans);
}
}
}