Billboard

hdu2795:http://acm.hdu.edu.cn/showproblem.php?pid=2795

题意:给一个h*w的公告牌,h是高度,w是宽度,一个单位高度1为一行,然后会有一些公告贴上去,公告是1*wi大小的长纸条,优先贴在最上面并且最左边的位置,如果没有空间贴得下,就输出-1,可以的话,就输出所贴的位置(第几行)。
 题解:用线段树来维护。把高度看成每一个节点,即每一行看成线段树的一个节点,而w看成底层节点的值,然后每个节点维护区间的最大值。由于h会达到10的9次方,但是只有200000的海报。随意当h大于200000时候,只需建立n==200000的树。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 using namespace std;
 6 int h,w,post,num,temp;//记录高度,长度,海报的数量, 
 7 struct Node{
 8     int left;
 9     int right;
10     int maxn;//区间的最大值 
11     int id;//底层的点的序号,用来标记行数 
12 }node[200002*4];
13 void build(int l,int r,int idx){
14     node[idx].left=l;
15     node[idx].right=r;
16     node[idx].id=0;
17     if(l==r){
18         node[idx].maxn=w;
19         node[idx].id=num++;//逐步记录 
20         return;
21     }
22     int mid=(l+r)/2;
23     build(l,mid,idx<<1);
24     build(mid+1,r,idx<<1|1);
25     node[idx].maxn=max(node[idx<<1].maxn,node[idx<<1|1].maxn);//pushup上去 
26 }
27 void update(int value,int idx){
28     if(node[idx].left==node[idx].right){//如果到达底层的点 
29         if(node[idx].maxn>=value){//如果满足要求,则更新节点的值 
30          node[idx].maxn-=value;
31          printf("%d\n",node[idx].id);//输出行号    
32         }
33     return;       
34     }
35     if(node[idx<<1].maxn>=value)update(value,idx<<1);//如果左儿子的manx满足要求,则优先考虑左边 
36     else if(node[idx<<1|1].maxn>=value)update(value,idx<<1|1);//如果左边不满足,右边满足则进入右儿子 
37     else {//否则则没有空间,输出-1,并且返回 
38     printf("-1\n");
39     return ;
40     }
41     node[idx].maxn=max(node[idx<<1].maxn,node[idx<<1|1].maxn);//更新父节点的maxn 
42 }
43 int main(){
44     while(~scanf("%d%d%d",&h,&w,&post)){//多组数据 
45         num=1;//初始化 
46      if(h<=200000)build(1,h,1);
47      else    build(1,200000,1);
48     for(int i=1;i<=post;i++){
49         scanf("%d",&temp);
50         update(temp,1);
51      }    
52     }
53 }
View Code

 

posted on 2013-11-18 18:49  天依蓝  阅读(238)  评论(0编辑  收藏  举报

导航