题目:
hdu2795 Billboard
题意:有一个h*w的公告板,现在将依次给你n个1*wi的海报,每次都要在不覆盖其他海报的前提下贴到最上且最左(要求先最上再最左)。问每张海报在第几行,贴不下的请输出-1;
题解:本题用线段树解决,每个节点有三个值:l,r,maxx;节点的[l,r]代表从第l行到第r行中最大剩余宽度为maxx。
线段树的思路:所有思路都是从暴力的思路优化来的,线段树也不例外,先思考本题暴力如何写:因为每张海报的高度为1,所以只需要暴力扫描每一行的剩余空间是否大于wi。这样复杂度为n*min(n,h),太大。所以我们转化思路,用线段树的思想来思考,用一个节点代表一段区域的最大值,就可以直接判断这段区域里是否有可以贴海报的地方。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<algorithm>
#include<map>
#include<vector>
using namespace std;
struct linetree{int l,r,maxx; }t[800000];
int h,w,n,ans;
void init(int l,int r,int p){
if(l>r) return ;
t[p].l=l;
t[p].r=r;
t[p].maxx=w;
if(l==r) return ;
int mid=(l+r)/2;
init(l,mid,2*p);
init(mid+1,r,2*p+1);
}
int q(int p,int a){
if(t[p].maxx<a){
ans=-1;return -1;
}
if(t[p].l==t[p].r){
t[p].maxx-=a;
ans=t[p].l;
}
else if(t[2*p].maxx>=a)
t[p].maxx=max(q(2*p,a),t[2*p+1].maxx);
else
t[p].maxx=max(t[2*p].maxx,q(2*p+1,a));
return t[p].maxx;
}
int main(){
while(cin>>h>>w>>n){
int minn=min(h,n);
init(1,minn,1);
int a;
for(int i=0;i<n;i++){
scanf("%d",&a);
q(1,a);
printf("%d\n",ans);
}
}
return 0;
}