hdu 2795 Billboard (线段树,找第一个大于w的点)

这道题一开始看,实在想不出跟线段树有什么关系,自己实在是太菜了。

给出h*w的广告版。每个广告是1*w的,给出m个广告,要每张广告尽量在上层尽量靠左,输出它所在的高度。假设放不下。就输出-1

这里的问题就是h给的非常大,可是 一共仅仅有m个广告,所以即使是一条广告占一条,那么也就仅仅须要m的高度,多余的高度没实用,假设m的高度的不能放下m条广告,那么即使h再高,也放不下,所以n应该是m和h的小值。一段存储下它所控制的区间的最大值,仅仅要最大值大于广告wi,那么第i条广告就能够放到这个区间内。 先推断左子树。左子树不合适后推断右子树(放上面),除非是当前的wi大于整段的最大值。否则一定能够放到广告版内,注意:在放入一个广告之后,改动全部的父节点的最大值。

 

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define maxn 200005
int hh[maxn<<2];
int h, w, n;
void pushup(int root){
	hh[root] = max(hh[root<<1],hh[root<<1|1]);
}
void build(int root, int l, int r){
	hh[root] = w;
	if(l == r) {
		return;
	}
	int m = (r+l)>>1;
	build(root<<1, l, m);
	build(root<<1|1, m+1, r);
}
int que(int root, int l, int r, int x){
	if(l == r){
		hh[root] -= x;
		return l;
	}
	int m = (r+l)>>1;
	int ans;
	ans = hh[root<<1] >= x ? que(root<<1, l, m, x) : que(root<<1|1, m+1, r, x);
	pushup(root);
	return ans;
}
int main() {
	while(~scanf("%d%d%d",&h,&w,&n)){
		h = min(h,n);
		build(1,1,n);
		int x;
		while(n--) {
			scanf("%d",&x);
			if(hh[1] < x){
				printf("-1\n");
			}else {
				printf("%d\n",que(1,1,h,x));
			}
		}
	}
	return 0;
}

 

先推断左子树。左子树不合适后推断右子树,除非是当前的wi大于整段的最大值。否则一定能够放到广告版内,注意,在放入一个广告之后,改动全部的父节点的最大值。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值