Billboard
Time Limit: 20000/8000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 25683 Accepted Submission(s): 10520
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.
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.
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
题意:有一块公告牌的尺寸为h*w(h为高,w为宽),有n个公告高都为1宽各不相同。每个公告都会尽可能的往左上角贴。也就是在尽量往更高的行数贴的同时,尽量往左边贴。输出每个公告贴在那个行数,如果所有行的空余区域都不足够贴下公告的话输出-1。
思路:用线段树的做法,线段树的叶子节点表示公告牌的每一行,并且在建树的时候每个节点都记录下代表区间中剩余可以贴海报空间的最大值。简而言之就是建一颗可以单点更新节点最大值的线段树。每次输入公告的宽度的时候都先和根节点的最大值比较(根节点代表的是整个公告牌中最大的剩余空间),如果根节点的最大值都小于公告的长度的话直接输出-1即可。此外因为公告要尽可能往左上角贴,所以在比较的时候先和左子树的最大值比较,不满足的话再和右子树的最大值比较。
最后要注意不要被h的范围吓到了,因为真正的叶子节点只有n个,所以如果h>n的时候要注意把h重新赋值,避免RE。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int MAXN=200000+10;
struct node
{
int l,r;
int Max;//记录区间中最大的剩余空间
}segTree[MAXN*4];
int a[MAXN];
void build(int root,int l,int r,int w)
{
segTree[root].l=l;
segTree[root].r=r;
segTree[root].Max=w;
if(l==r)
return;
int mid=(l+r)>>1;
build(root<<1,l,mid,w);
build(root<<1|1,mid+1,r,w);
}
void update(int root,int x)
{
if(segTree[root].l==segTree[root].r)
{
//因为在主函数当中我们先比较了根节点的最大值和输入的公告长度的大小
//所以进行节点更新操作的话肯定是能找到能够放下公告的地方的
//所以搜索到叶子节点的时候直接输出即可
printf("%d\n",segTree[root].l);
//更新叶子节点的最大值
segTree[root].Max-=x;
return;
}
if(segTree[root<<1].Max>=x)
update(root<<1,x);
else
update(root<<1|1,x);
//回溯更新节点最大值
segTree[root].Max=max(segTree[root<<1].Max,segTree[root<<1|1].Max);
}
int main()
{
int h,w,n,i;
while(scanf("%d %d %d",&h,&w,&n)!=EOF)
{
//因为h的范围太大,但是真正的叶子节点只有n个
//所以为了避免数组越界缩小h 的值
if(h>n) h=n;
for(i=0;i<n;i++)
scanf("%d",&a[i]);
build(1,1,h,w);
for(i=0;i<n;i++)
{
if(segTree[1].Max>=a[i])
update(1,a[i]);
else
printf("-1\n");
}
}
return 0;
}