HDU 2795 Billboard

 

题意:有一个h*w的广告牌,在这上要贴一些广告,每个广告的高度为一个单位,宽为WI,这样广告牌就可以分成h个层。逐个给出一些广告所占的宽度问你这个广告可以放在第几层(广告尽量靠上靠又)。

 

题解:线段树。把每一层抽象成一个数,在这些数中找出一个层数最小且大于WI的数,并进行更新(当这一层被一个广告占用一部分时,这个数就减去相应的宽度)。

这里还有个问题:h大到10^9,如果按给定的h建树的话肯定会爆内存!这里注意到n<=20,000,最多占用20,000行,所以只要按如下方式处理就可以了。

if(h>n)h=n;

 

AC代码:

 

View Code
 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 const int maxn=10000000;
 5 int maxnum[maxn];
 6 int max(int a,int b){
 7     return a>b?a:b;
 8 }
 9 void Build(int l,int r,int pos,int w){
10     if(l==r){
11         maxnum[pos]=w;
12         return;
13     }
14     int mid=(l+r)>>1;
15     Build(l,mid,pos*2,w);
16     Build(mid+1,r,pos*2+1,w);
17     maxnum[pos]=w;
18 }
19 void Query(int wi,int l,int r,int pos){
20     if(maxnum[pos]<wi){
21         printf("-1\n");
22         return;
23     }
24     if(l==r){
25         maxnum[pos]-=wi;
26         printf("%d\n",l);
27         return;
28     }
29     int mid=(l+r)>>1;
30     if(maxnum[pos*2]>=wi)Query(wi,l,mid,pos*2);
31     else Query(wi,mid+1,r,pos*2+1);
32     maxnum[pos]=max(maxnum[pos*2],maxnum[pos*2+1]);
33 }
34 int main()
35 {
36     //freopen("in.txt","r",stdin);
37     int h,w,n,wi;
38     while(scanf("%d %d %d",&h,&w,&n)!=EOF){
39         if(h>n)h=n;
40         Build(1,h,1,w);
41         while(n--){
42             scanf("%d",&wi);
43             Query(wi,1,h,1);
44         }
45     }
46     return 0;
47 }

 

posted on 2012-10-12 21:57  Acmer_Roney  阅读(136)  评论(0编辑  收藏  举报

导航