Billboard 线段树

Billboard

Time Limit: 20000/8000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 24453    Accepted Submission(s): 10054


Problem Description
At the entrance to the university, there is a huge rectangular billboard of size h*w (h is its height and w is its width). The board is the place where all possible announcements are posted: nearest programming competitions, changes in the dining room menu, and other important information.

On September 1, the billboard was empty. One by one, the announcements started being put on the billboard.

Each announcement is a stripe of paper of unit height. More specifically, the i-th announcement is a rectangle of size 1 * wi.

When someone puts a new announcement on the billboard, she would always choose the topmost possible position for the announcement. Among all possible topmost positions she would always choose the leftmost one.

If there is no valid location for a new announcement, it is not put on the billboard (that's why some programming contests have no participants from this university).

Given the sizes of the billboard and the announcements, your task is to find the numbers of rows in which the announcements are placed.
 

Input
There are multiple cases (no more than 40 cases).

The first line of the input file contains three integer numbers, h, w, and n (1 <= h,w <= 10^9; 1 <= n <= 200,000) - the dimensions of the billboard and the number of announcements.

Each of the next n lines contains an integer number wi (1 <= wi <= 10^9) - the width of i-th announcement.
 

Output
For each announcement (in the order they are given in the input file) output one number - the number of the row in which this announcement is placed. Rows are numbered from 1 to h, starting with the top row. If an announcement can't be put on the billboard, output "-1" for this announcement.
 

Sample Input
  
  
3 5 5 2 4 3 3 3
 

Sample Output
  
  
1 2 1 3 -1
 

Author
hhanger@zju
 

Source
 

Recommend
lcy

题意为有一块宽为L高为H的板子,上面要贴宽为w,高度统一为1的通知单。高度为1,这样板子就可以从上到下分为H行,编号1到H,依次地放传单,每次都尽可能地向上,向左放,输出每个通知单放的位置(即在板子的第几行),如果板子上没有位置可放,就输出-1. 用线段树来做,首先建树,叶子节点数为板子的高度即行数,节点维护区间高度的最大“空隙”,即(放了通知单以后,行内还有多少宽度可以使用的最大值)。因为要尽可能地向上放,所以左儿子优先于右儿子优先访问,放每个宣传单时,找到节点维护的最大值大于等于该宣传单的宽度时,就判断该最大值来自左儿子还是右儿子,如果两者一样,优先左儿子,如果左儿子是叶子节点,则它存放的宽度值(也是它当前的最大值,因为它没有子节点)减去该宣传单的宽度,然后向上更新父节点。

#include <iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
int va[10000500>>2];
int h,w,n;
void build(int i,int l,int r)
{
    if(l==r)
    {
        va[i]=w;
        return;
    }
    int mid=(l+r)>>1;
    build(i<<1,l,mid);
    build(i<<1|1,mid+1,r);
    va[i]=max(va[i<<1],va[i<<1|1]);
}
int query(int i, int l, int r, int c)
{
    if(va[i] < c)
        return -1;
    if(l == r){
        va[i] -= c;
        return l;
    }
    int mid = (l+r)>>1;
    int ans = query(i<<1, l, mid, c);
    if(ans == -1)
        ans = query(i<<1|1, mid+1, r, c);
    va[i]=max(va[i<<1],va[i<<1|1]);
    return ans;
}
int main()
{
    while(~scanf("%d%d%d",&h,&w,&n))
    {
        if(h>n)
            h=n;
        build(1,1,h);
        while(n--)
        {
            int a;
            scanf("%d",&a);
            printf("%d\n",query(1,1,h,a));
        }


    }
    return 0;
}
人一我百!人十我万!永不放弃~~~怀着自信的心,去追逐梦想。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

じ☆夏妮国婷☆じ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值