hdu 2795-Billboard

Billboard

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


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
 【题意】: 给你一块 w*h 的板,然后让你用一些 1*x 的木块去填,每次填的时候总是选择行靠前的,假设能够放在该行上。则会选择列靠前的,如今让你对每一种木块 输出它所放在的行。假设不能放上去则输出 -1

【分析】: 这题一開始看到数据范围是 10^9 吓了一跳。只是细致分析能够发现,事实上真正实用的仅仅是 min(h,n) 其他都是浪费的,那么好了,就能够往下做了 非常明显的是一个区间染色问题。也非常easy的就想到能够用线段树来搞 只是这题是分成若干段后的染色。一開始可能会认为可能须要建立多个线段树来针对每一段分别来搞 实际上,这题仅仅须要一个线段树就能够搞定了 建一棵 [1,len] len=min(h,n) 的线段树,每个线段维护一个最大长度域 maxLen(这里因为不同组之间的线段是不能拼在一起的,因此维护的时候仅仅要简单的 max 一下即可了,不须要左右的讨论。再维护两个域 lmax,rmax)。一開始的时候 maxLen 都为 w 。然后维护这个域的时候仅仅须要简单的 max 一下即可了(每一行事实上都是独立的。用线段树维护的仅仅是能够方便的找到最优的行的位置) 之后就是利用二分逼近的思想来查找那个符合条件的最优行的位置,找到之后做出对应的改动。即 update 该行的 maxLen 域即可了 
代码:
#include<cstdio> 
#include<iostream>
using namespace std;
#define maxn 200005 
#define L(i) (i<<1) 
#define R(i) (i<<1|1) 
int h,w,n; 
struct node 
{
	int left,right,len;
};
inline int max(int a,int b)
{
	return a>b?a:b;
}
inline int min(int a,int b)
{
	return a<b?a:b;
}
struct SegTree 
{ 
	node tree[maxn*4];
	void update(int p)
	{ 
		tree[p].len=max(tree[L(p)].len,tree[R(p)].len);
	}
	void build(int p,int left,int right)
	{
		tree[p].left=left;
		tree[p].right=right;
		tree[p].len=w;
		if(left==right) return;
		int mid=(left+right)>>1;
		build(L(p),left,mid);
		build(R(p),mid+1,right);
	}
	void query(int p,int x,int& ans)
	{
		if(tree[p].len<x)
		{
			ans=-1;
			return;
		};
		if(tree[p].left==tree[p].right)
		{
			tree[p].len-=x;
			ans=tree[p].left;
			return;
		}
		if(tree[L(p)].len>=x)
			query(L(p),x,ans); //这个地方等号要等到才行
		else if(tree[R(p)].len>=x) 
			query(R(p),x,ans);
		update(p);
	}
}seg;
int main()
{
	int i,j,k,len,ans;
	while(scanf("%d%d%d",&h,&w,&n)!=EOF)
	{
		len=min(h,n);
		seg.build(1,1,len);
		while(n--)
		{
			scanf("%d",&k);
			ans=-1;
			seg.query(1,k,ans);
			printf("%d\n",ans);
		}
	}
	return 0;
}  

转载于:https://www.cnblogs.com/blfshiye/p/5058956.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值