HDU 2795 放模板 (线段树_维护最大值,好题)

题意:有个公告板,大小为h*w,要贴n张公告,每个公告的长度是k,高度固定为1,公告放的要尽可能靠上并尽可能靠左,每给出一张公告,要求这个公告在满足要求的情况下放在了第几层。

Sample Input
  
  
3 5 5 2 4 3 3 3
 

Sample Output
  
  
1 2 1 3 -1
 

题意:h*w的木板,放进一些1*L的物品,求每次放空间能容纳且最上边的位子
思路:每次找到最大值的位子,然后减去L
线段树功能:query:区间求最大值的位子(直接把update的操作在query里做了)


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=2e5+10;
int c[maxn<<2];
int h,w;
void build(int l,int r,int rt)
{
	c[rt]=w;
	if(l==r) return;
	int mid=(l+r)>>1;
	build(l,mid,rt<<1);
	build(mid+1,r,rt<<1|1);
}
int query(int num,int l,int r,int rt)
{
	if(l==r) {
		c[rt]-=num;
		return l;
	}
	int mid=(l+r)>>1;
	int ans=0;
	if(num<=c[rt<<1]) ans=max(ans,query(num,l,mid,rt<<1));
	else ans=max(ans,query(num,mid+1,r,rt<<1|1));
	c[rt]=max(c[rt<<1],c[rt<<1|1]);
	return ans;
}

int main()
{
	int n,num;
	while(scanf("%d%d%d",&h,&w,&n)!=EOF) {
		if(h>n) h=n;
		build(1,h,1);
		while(n--) {
			scanf("%d",&num);
			if(num>c[1]) printf("-1\n");
			else printf("%d\n",query(num,1,h,1));
		}
	}
	return 0;
}


线段树有点二分的思想,,,用线段树去维护查找,因为我们要去查找最上面的所能放下木板的广告位,于是就用线段树来维护,根节点就是最大的广告位,如果木板大于最大的广告位就不行了。当放入木板后,广告位的容量就要减少,就直接单点更新。。


线段树绝对的好题啊!!!!!要理解线段树后才能理解这题。mark




2016.3.8 复习线段树又重新敲了一遍


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
const int N = 2e5 + 10;
int c[N<<2];

void build(int l,int r,int rt,int num)
{
	if(l==r) {
		c[rt]=num;
		return;
	}
	int mid=(l+r)>>1;
	if(l<=mid) build(l,mid,rt<<1,num);
	if(r>mid) build(mid+1,r,rt<<1|1,num);
	c[rt]=num;
}

int ask(int l,int r,int rt,int num)
{
	int ans=-1;
	if(c[rt]<num) return ans;
	if(l==r && c[rt]>=num) {
		c[rt]-=num;
		return ans=l;
	}
	int mid = (l+r)>>1;
	if(c[rt<<1]>=num) ans=ask(l,mid,rt<<1,num);
	else if(c[rt<<1|1]>=num) ans=ask(mid+1,r,rt<<1|1,num);
	c[rt]=max(c[rt<<1],c[rt<<1|1]);
	return ans;
}

int main()
{
	int h,w,q,i,j,n;
	while(scanf("%d%d%d",&h,&w,&n)!=EOF) {
		build(1,min(h,n),1,w);
		for(i=1;i<=n;i++) {
			scanf("%d",&q);
			int t = ask(1,min(h,n),1,q);
			if(t) printf("%d\n",t);
			else printf("-1\n");
		}
	}
	return 0;
}







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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值