HDU 2795 Billboard(线段树:找到线段树中>=给定值的第一个元素位置 并 更新该点)
http://acm.hdu.edu.cn/showproblem.php?pid=2795
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.
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.
分析:
建立一颗线段树,线段树维护的每个元素(不是指树的节点哦)代表广告牌的一行的当前剩余最大空间maxv。比如i节点维护区间[l,r],那么r元素代表广告牌的第r行。即maxv[i]就是i节点维护的广告牌的那些行中,剩余空间的最大值。
最多只有n(n<=20W)个公共,且一条公共如果连一整行都放不下(即wi>w),直接输出-1即可。所以我们线段树最多只需要维护20W个元素。就算h有10亿,后面那些行根本是浪费。
注意:如果h比n小,那么线段树的节点总数定为h个,否则定位n个.如果wi>w,那么直接输出-1.
现在我们依次读入wi,找到能放下wi的序号最小的线段树叶节点,然后更新线段树即可。这个查询过程我们可以写query函数来查询,当然也可以用如下做法:将query嵌入update中。
其中线段树中节点维护的信息是:本节点控制的区间[L,R]内的叶节点的最大剩余空间maxv[i]。如果maxv[i]>wi说明这个节点的子树有叶子能放下wi,优先往左子树找即可.
本线段树不用query,只需要update并在update的时候返回需要的信息即可。
AC代码:2437ms
<span style="font-size:18px;"><span style="font-size:18px;">#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int H,W,n,Q;
const int MAXN=200000+100;
int maxv[MAXN*4];
int id[MAXN*4];
int cnt;
#define lson i*2,l,m
#define rson i*2+1,m+1,r
void PushUp(int i)
{
maxv[i]=max(maxv[i*2] , maxv[i*2+1]);
}
void build(int i,int l,int r)
{
if(l==r)
{
maxv[i]=W;
id[i]=++cnt;
return ;
}
int m=(l+r)/2;
build(lson);
build(rson);
PushUp(i);
}
int update(int w,int i,int l,int r)
{
if(w>maxv[i])
return -1;
if(l==r)
{
maxv[i]-=w;
return id[i];
}
int res=-1;
int m=(l+r)/2;
if(maxv[i*2]>=w)res = update(w,lson);
else if(maxv[i*2+1]>=w)res= update(w,rson);
PushUp(i);
return res;
}
int main()
{
while(scanf("%d%d%d",&H,&W,&Q)==3)
{
cnt=0;
n = min(Q,H);//线段树叶节点的最大数目
build(1,1,n);
for(int i=1;i<=Q;i++)
{
int w;
scanf("%d",&w);
printf("%d\n",update(w,1,1,n));
}
}
return 0;
}</span></span>