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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章