HDU-2795 Billboard
题目大意:给一个长方形的广告牌,往上面贴 n 张 广告纸。
广告牌的宽度、高度分别为 h (按 1 至 h 一共 h 层算)、 w ,广告纸的规格为 高 1,wi 。从第一张开始往上面贴,每次优先考虑上层的,靠左贴,如果贴不下则考虑下一层,从 1 至 h 层。输出该广告纸所贴到的层数;如果 1 到 h 层都贴不下了,则输出 -1.
Sample Input
3 5 5
2
4
3
3
3
Sample Output
1
2
1
3
-1
大致思路:
线段树,开辟MAX[ ]数组,记录线段(i j 从i 层到 j 层) 的未使用宽度的 Max,若是元线段则为具体某层的未使用宽度。
每次输入 广告单 宽度 wi,查找树根,如果max < wi ,说明最大的剩余宽度都不能容纳 wi ,返回 -1;如果 max > wi , 说明 1 至 h 层至少有一层能容纳 wi。然后向下层递归。
当搜索至 元线段,即叶子节点时,返回层数(这里用全局变量 num 记录),将该叶子节点的 max 值更新,然后返回上一层,逐层更新 max 值。
注意点:开辟 MAX[ ] 数组,以及调用build(,, )函数时,由题意最多需要 n 层。而这里(1 <= h,w <= 10^9; 1 <= n <= 200,000),差距相当大 。因为 h > n 的时候,实际最多使用 n 层。所以 if ( h>n ) h=n; 。
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int Max = 200002;
int MAX[Max<<2];
int h,w,n;
int num;
void PushUp(int id)
{MAX[id]=max(MAX[id*2],MAX[id*2+1]); }
void build(int l,int r,int id)
{MAX[id]=w;
if(l==r) return ;
int mid=(l+r)/2;
build(l,mid,id*2);
build(mid+1,r,id*2+1);
return;
}
void QU(int x,int l,int r,int id)
{if(l==r)
{ num=l;
MAX[id]-=x;
return;
}
int mid=(l+r)/2;
if(x<=MAX[id*2])
{ QU(x,l,mid,id*2);
PushUp(id);
return;
}
if(x<=MAX[id*2+1])
{ QU(x,mid+1,r,id*2+1);
PushUp(id);
return;
}
}
int main()
{ //freopen("in.txt","r",stdin);
while(scanf("%d%d%d",&h,&w,&n)!=EOF)
{ int in;
if(h>n) h=n; //很重要
build(1,h,1);
for(int i=1;i<=n;i++)
{ scanf("%d",&in);
if(MAX[1]<in) printf("-1");
else { QU(in,1,h,1); printf("%d\n",num); }
}
}
return 0;
}