题目描述:
有一座延绵不断、跌宕起伏的山,最低处海拔为0米,最高处海拔不超过8848米。从这座山的一端走到另一端的过程中,每走 1 米海拔高度就升高 1 米或者降低 1 米。有 Q 个登山队计划在这座山的不同区段登山,当他们攀到各自区段内的最高峰时,就会插上他们的队旗。请你写一个程序找出他们插旗的高度。
大致思路:
其实这道题就是给你一列数,然后在给你一些询问,A到B这段区间最大的数是多少。很明显,这就是一道线段树的基础题。
对于线段树,我们在进行树的遍历时,下去的过程中是可以进行一些标记操作的,而回溯的过程中是可以进行动态规划的。对于这道题,这棵线段树是静态的,所以不存在标记操作,那么只要建好树以后进行一次树形动规就行。
F[a,b]表示a到b这段区间的最大值,那么
F[a,b]=max{f[a,m],f[m+1,b]},其中m=(a+b) div 2。
然后,对于每个询问(a,b),我们只需要在查找线段树(a,b)的过程中记录所有经过节点的最大f值即可。
对于题目的数据范围,因为询问数较少,所以最好通过询问,把区间进行离散化。
代码:#include <cstdio>
#include <algorithm>
using namespace std;
#define lowbit(x) ((x)&-(x))
#define MAXN 1000000
long tArr[MAXN+10],a[MAXN+10];
long n;
void build(){
for(long i=1;i<=n;i++){
tArr[i]=max(tArr[i],a[i]);
long p=i;
while(p+lowbit(p)<=n){
if(tArr[p+lowbit(p)]<tArr[p]){
tArr[p+lowbit(p)]=tArr[p];
p+=lowbit(p);
}else{
break;
}
}
}
}
long getMax(long l,long r){
//printf("getMax(%ld,%ld)\n",l,r);
long p=r;
long res=0;
while(p>=l){
if(p-lowbit(p)+1>=l){
res=max(res,tArr[p]);
p-=lowbit(p);
}else{
res=max(res,a[p]);
p--;
}
//printf("p=%ld res=%ld\n",p,res);
}
return res;
}
int main(){
scanf("%ld",&n);
n++;
for(long i=1;i<=n;i++){
scanf("%ld",&a[i]);
}
build();
/*
for(long i=1;i<=n;i++){
printf("a[%ld]=%ld tArr[%ld]=%ld\n",i,a[i],i,tArr[i]);
}
*/
long q;
scanf("%ld",&q);
for(long i=1;i<=q;i++){
long st,ed;
scanf("%ld%ld",&st,&ed);
st++;
ed++;
printf("%ld\n",getMax(st,ed));
}
return 0;
}