标签:des style blog class code c
3 5 5 2 4 3 3 3
1 2 1 3 -1
最近在学习线段树, 这道题是我搜“线段树练习”时找到的,那么这道题的解法也就是用线段树解决。但是读完题目很容易想到的是暴力,一开始就想到用线段树我觉得不是那么自然。。说一下题意: 一块广告牌长h,宽h,还有m条长度不同的广告,但每条广告的宽度都是1。每次贴广告都往左上贴,能贴上的就输出在第几行,否则输出-1。
我们可以把广告牌假想成一条一条的 , 每条长度为w ,宽度就为1,共有h条,那么区间就是[1~h],可以用线段树维护区间的所有条的剩余的长度 的最大值。(整个题目一大半就在这了) ,叶节点就保存的是每条的剩余。
说一下我写的时候碰到的一些问题,递归左儿子的时候如果把当前的广告插到了左儿子,那么就不必考虑右儿子,用ok标记。
还有就是RE了好多次的一个地方,输入的h可能很大,数组会爆,考虑到如果h超过了m,那么不会存在广告宽度不够用的情况,可以人为的把广告牌改短,改到m,足矣。
但是不可以在建树的时候直接用m,考虑假如m大于h,那么相当于把广告牌加长了,这是不允许的。
#include<stdio.h>
int h,w,m,x,ans,ok,res[800050];
int _max(int a,int b)
{
return a>b?a:b;
}
void pushup(int o)
{
res[o]=_max(res[o<<1] , res[o<<1|1]);
}
void build(int o,int l,int r)
{
res[o]=w; //优化一点,也可以递归下去到最后再修改然后pushup
int m=(l+r)>>1;
if(l == r) return ;
else {
build(o<<1,l,m);
build(o<<1|1,m+1,r);
}
}
void update(int o,int l,int r)
{
int m=(l+r)>>1 ;
if(res[o] >= x) {
if(l == r) {
res[o]-=x;
ans=l;
ok=1;
} else {
ok=0;
update(o<<1,l,m);
if(!ok) update(o<<1|1,m+1,r);
pushup(o);
}
}
}
int main()
{
while(~scanf("%d%d%d",&h,&w,&m)) {
if(h>m) h=m; // 重点,想了一会才明白,各种RE
build(1,1,h);
while (m--) {
scanf("%d",&x);
ans=-1;
update(1,1,h);
printf("%d\n",ans);
}
}
return 0;
}
HDU 2795 Billboard (RE的可以看一看),布布扣,bubuko.com
标签:des style blog class code c
原文地址:http://blog.csdn.net/u013923947/article/details/25885079