HDU 2795 Billboard 线段树活用

题目大意:在h*w 高乘宽这样大小的 board上要贴广告,每个广告的高均为1,wi值就是数据另给,每组数组给了一个board和多个广告,要你求出,每个广告应该贴在board的哪一行,如果实在贴不上,就输出-1;

这个题目也难以想到居然是用线段树来做

我们需要考虑的是,线段树究竟表示的是什么数据。在这个题目里,由于每个广告的高都为1,是不是好像感觉每一行都是一个叶子节点一样。没错,就是这样。。。化抽象为具体一点,那就是把这个board给竖起来,这样最底部的孩子存贮了当前行的空闲宽度,每个父节点都是左右孩子的max。

其实思路这样理一下,感觉其实很简单,是把。

还要注意的一点是,虽然题目说h 和 w高达10的九次方,但并不意味着我线段树要建如此大(事实上真要建也建不了),由于广告最多只有200000个,所以,你想,底层叶子最多,也就每个广告占一行,那也就是这么大。。。因此线段树的大小真心不能只看表面

#include <iostream>
#include <cstdio>
#include <cstring>
#define Lson (x<<1),l,mid
#define Rson (x<<1|1),mid+1,r
#define maxn 200005
using namespace std;
int d[maxn*4];
int max(int a,int b)
{
    return a>b ? a:b;
}
void getup(int x)
{
    d[x]=max(d[x<<1],d[x<<1|1]);
}
void build (int wid,int x,int l,int r)
{
    if (l==r){d[x]=wid;return;}
    int mid=(l+r)/2;
    build(wid,Lson);
    build(wid,Rson);
    getup(x);
}
/*void update(int a,int x,int l,int r)
{
    if (l==r)
    {
        d[x]-=a;
    }
    int mid=(l+r)/2;
    if (a<=d[x<<1]) update(a,Lson);
    else update(a,Rson);
    getup(x);
}*/
int query(int a,int x,int l,int r)
{
    if (l==r)
    {
        if (d[x]<a) return -1;//此时根本就贴不上
        else  {d[x]-=a;return l;}
    }
    int mid=(l+r)/2;
    int ret=0;
    if (a<=d[x<<1]) ret=query(a,Lson);
    else ret=query(a,Rson);
    if (ret>0) getup(x);//及时更新父节点
    return ret;
}
int main()
{
    int h,wid,q;
    while (scanf("%d %d %d",&h,&wid,&q)!=EOF)
    {
        if (h>q) h=q;//注意h过大的时候,以广告数q为宗旨。
        build(wid,1,1,h);
        int i,j;
        for (i=1;i<=q;i++)
        {
            int a;
            scanf("%d",&a);
            int ans=query(a,1,1,h);
            printf("%d\n",ans);
            //if (ans!=-1)
             //update(a,1,1,h);
        }
    }
    return 0;
}

 

posted @ 2013-08-15 10:05  KRisen  阅读(142)  评论(0编辑  收藏  举报