登山

题目描述:

有一座延绵不断、跌宕起伏的山,最低处海拔为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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值