hdu-2795Billboard
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
Sample Output
题目大意:
有一个h*w的公告牌。现在有n个广告牌,要挂在公告牌上。广告牌的面积为1*x。挂牌的规则是:尽量选择公告牌的顶部,而且尽量靠左边。要求广告牌的放置的位置是在第几行。如果没有地方放了,就输出-1。
解题思路:
构建一棵线段树,叶子节点便是公告牌的第几行,叶子节点的值,便是该行还剩下的空间数。每个父节点保存子节点的最大值,利用线段树求解。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<iostream>
using namespace std;
#define maxn 222222
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int sum[maxn<<2];
void push(int rt)
{
sum[rt]=max(sum[rt<<1],sum[rt<<1|1]);//父亲节点保存子节点的最大值
}
void build(int value,int l,int r,int rt)
{
if(l==r)
{
sum[rt]=value;//公告牌每行初始的空间为公告牌的宽
return ;
}
int m=(r+l)>>1;
build(value,lson);
build(value,rson);
push(rt);
}
int query(int p,int l,int r,int rt)
{
if(l==r)
{
sum[rt]-=p;//每次放置完一个广告牌之后就要更新这一行的空间
return l;//输出广告牌放在第几行
}
int m=(l+r)>>1;
int ans=0;
if(sum[rt<<1]>=p)//根据题目要求,如果左子树存在可以放置该广告牌的位置,就优先考虑放在左子树
ans=query(p,lson);
else
ans=query(p,rson);
push(rt);
return ans;
}
int main()
{
int h,w,n;
while(~scanf("%d%d%d",&h,&w,&n))
{
if(h>n)h=n;//注意,当h>n的时候,就可以缩小h的值了,减少建树时的内存浪费。(因为h>n时,最坏的情况就是每行放一个广告,h>n的部分没用)
build(w,1,h,1);
while(n--)
{
int x;
scanf("%d",&x);
if(sum[1]<x) printf("-1\n");//因为根节点所存放的值,是所有叶子节点中的最大值。如果根节点的空间都小于该广告牌的面积,则说明放不下了
else printf("%d\n",query(x,1,h,1));
}
}
return 0;
}