Billboard 巧妙运用线段树

在学校的入口处有一个巨大的矩形广告牌,高为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;
}

猜你喜欢

转载自blog.csdn.net/qq_41703679/article/details/81292018