/*
hdu 2795 Billboard 线段树
题意:一个宣传板,h行w列,每个宣传条占1行wi列
现给出一些宣传条,希望贴在最靠上,然后最靠左的地方,输出行号,若无法贴下输出-1
刚开始还以为是一道水题
看过比人的报告才知道是线段树
每个叶子节点记录一行剩余的空余位置,这样貌似需要(1 <= h<= 10^9)个叶子节点
但是, 1 <= n <= 200,000 就算一个条子占一行,也顶多 200,000行
线段树的魅力在于他的整体接受或拒绝
*/
#include<iostream>
using namespace std;
#define N 200010
struct node
{
int l,r,w;//这个区间内 剩余最多的那行的剩余量
}segtree[N<<2];
int h,w,n;
inline int min(int a,int b){return a<b?a:b;}
void build(int l,int r,int no)
{
if(l==r)
{
segtree[no].w=w;
segtree[no].r=r;
segtree[no].l=l;
}else
{
segtree[no].w=w;
segtree[no].r=r;
segtree[no].l=l;
int mid=(l+r)>>1;
build(l,mid,no*2);
build(mid+1,r,no*2+1);
}
}
int query(int l,int r,int no,int cha)
{
int ret;
if(segtree[no].w<cha)//若剩余最多的都无法满足,那么这个区间所有行都无法满足要求,这就是线段树的整体拒绝
return -1;
if(l==r)//若是叶子节点 满足要求 则从这行中给他分配位置
{
segtree[no].w-=cha;
return l;//返回行号
}
if(segtree[no*2].w>=cha)//若左区间满足 在左区间找 因为 上层优先么
{
ret=query(l,(l+r)>>1,no*2,cha);
segtree[no].w=segtree[no*2].w > segtree[no*2+1].w ? segtree[no*2].w : segtree[no*2+1].w;
return ret;
}
else //然后才是右区间
{
ret=query(((l+r)>>1)+1,r,no*2+1,cha);
segtree[no].w=segtree[no*2].w > segtree[no*2+1].w ? segtree[no*2].w : segtree[no*2+1].w;
return ret;
}
}
int main()
{
while(cin>>h>>w>>n)
{
int nmin=min(h,n);
build(1,nmin,1);
while(n--)
{
cin>>h;
int ke=query(1,nmin,1,h);
printf("%d\n",ke);
}
}
return 0;
}
hdu 2795 Billboard 线段树
最新推荐文章于 2019-04-08 23:33:46 发布