[ACM] hdu 2795 Billboard (线段树)

本文详细介绍了公告板布局算法的实现过程,包括输入参数处理、构建线段树、查询算法实现,以及如何根据算法输出公告单在公告板上的放置行数。通过实例演示,清晰展示了算法的核心思想及应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Billboard

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


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

 

 

解题思路:

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

做了几道线段树的题目,觉得首先要弄清楚叶子节点代表的是什么,并依此建树,毕竟,建树是第一步,每个节点维护的是什么,实现什么样的功能。

代码:

#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

const int maxn=200005;
int Max[maxn<<2];
int h,w,n;

void PushUp(int rt)//维护最大”空隙“
{
    Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);
}
void build(int l,int r,int rt)//高度有多少,建立的树就有多少个叶子节点,每个节点代表高度中的每一行
{
    /*if(l==r)
    {
        m[rt]=w;
        return;
    }*/ //错误代码,每个节点都得赋值为w
    Max[rt]=w;
    if(l==r)
        return;
    int m=(r+l)>>1;
    build(lson);
    build(rson);
    //PushUp(rt);//不用加这一句话。
}
int query(int x,int l,int r,int rt)
{
    if(l==r)
    {
        //m[l]-=x;//错误
        Max[rt]-=x;//当前节点
        return l;
    }
    int m=(r+l)>>1;
    //int ans=0;//错误,不能赋值
    int ans;
    ans=(Max[rt<<1]>=x)?query(x,lson):query(x,rson);//优先查询左儿子
    PushUp(rt);//更新
    return ans;
}
int main()
{
    while(scanf("%d%d%d",&h,&w,&n)==3)
    {
        h=min(h,n);//当查询的个数n小于h时,h=n的情况是一样的,因为下面高度的板子用不到,每行一个就足够了
        build(1,n,1);
        int x;
        while(n--)
        {
            scanf("%d",&x);
            if(Max[1]<x)//所有行的最大空还小于x,放不下
            {
                printf("-1\n");
            }
            else
                printf("%d\n",query(x,1,h,1));
        }
    }
    return 0;
}


 

转载于:https://www.cnblogs.com/sr1993/p/3697900.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值