在学校的入口处有一个巨大的矩形广告牌,高为h,宽为w。所有种类的广告都可以贴,比如ACM的广告啊,还有餐厅新出了哪些好吃的,等等。。
在9月1号这天,广告牌是空的,之后广告会被一条一条的依次贴上去。
每张广告都是高度为1宽度为wi的细长的矩形纸条。
贴广告的人总是会优先选择最上面的位置来帖,而且在所有最上面的可能位置中,他会选择最左面的位置,而且不能把已经贴好的广告盖住。
如果没有合适的位置了,那么这张广告就不会被贴了。
现在已知广告牌的尺寸和每张广告的尺寸,求每张广告被贴在的行编号。
Input
多组样例,不超过40个。
对每组样例,第一行包含3个整数h,w,n(1 <= h,w <= 10^9; 1 <= n <= 200,000) -广告牌的尺寸和广告的个数。
下面n行每行一个整数 wi (1 <= wi <= 10^9) - 第i张广告的宽度.
Output
对每张广告,输出它被贴在的行编号(是1到h之间的数),顶部是第一行。如果某广告不能被贴上,则输出-1。
Sample Input
3 5 5
2 4 3 3 3
Sample Output
1
2 1 3 -1
题目大意:有一个h*w的公告板,要往上面放n个广告,每个广告宽为1,长为w[i],优先放在上面,从左边放起。
问题不难,简单的线段树模板题,
用父节点保存子节点剩余的最大的广告长度。
#include <cstdio>
#include <limits.h>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;
int tree[800003];
int h,w,n,x;
int Query(int num,int l,int r,int wi){ //num是当前节点,[l,r]是当前节点区间,wi是广告的长度
if (l==r) { //如果l==r则说明到达叶子节点
tree[num]-=x; //把节点上的长度减掉x
return l; //返回节点编号
}
int m=(l+r)>>1;
int res=0;
if (tree[num<<1]>=wi) res=Query(num<<1,l,m,wi); //优先查询左子树
else res=Query(num<<1|1,m+1,r,wi);
tree[num]=max(tree[num<<1],tree[num<<1|1]); //更新父节点的值
return res; //返回查询到的节点编号
}
int main(){
while (scanf("%d%d%d",&h,&w,&n)!=EOF)
{
if (h>n) h=n; //不可能用到比n更多的行数
for (int i=1; i<(h<<2); i++) tree[i]=w; //相当于建树
while (n--)
{
scanf("%d", &x);
if (tree[1]<x) printf("-1\n"); //总区间的最大值小于广告长度,则无法放置
else printf("%d\n", Query(1,1,h,x)); //查询[1,h]
}
}
return 0;
}