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 ",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 "); 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 }