您的位置:首页 > 其它

HDOJ-2795-Billboard 解题报告

2014-11-25 14:27 369 查看
线段树题。题意:大学门口有一个巨大的矩形布告板,高度为h,宽度为w。这个广告牌会被贴上许多高度为1宽度未知的公告,为了使公告尽可能的被更多人看到,所以公告会被贴得尽量高并且总是选择最靠左边的位置。假设布告板的高度从高到低编号为1~h,现在有n个公告要贴,告诉你每一个公告的宽度,如果这个公告能被贴在布告板上,输出它的高度编号,否则输出-1。

我的解题思路:注意到h与w的范围可以达到10的9次方,如果以h的范围来建树应该会爆内存。但是n的最大值不过是20万而已,分析一下可知n个公告最多占用布告板的高度为n。所以应该可以用n的范围来开内存,然后以min(n, h)的值作为区间范围来建树。节点存储高度编号区间的剩余可用宽度最大值就可以了。

我的解题代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

#define N 200002
#define LL(x) (x << 1)
#define RR(x) (x << 1 | 1)

struct ST
{
    int left, right, mid;
    int maxvalue;       //最大剩余空间
    void init()
    {
        mid = (left + right) >> 1;
    }
};

ST node[N<<2];
int h, w, n;
int m;

void BuildTree(int left, int right, int x);

int Update(int a, int x);

void PushUp(int x);

int main()
{
    int a;
    while (~scanf("%d %d %d", &h, &w, &n))
    {
        m = h > n ? n : h;  //判断建树区间
        BuildTree(1, m, 1);
        while (n--)
        {
            scanf("%d", &a);
            if (node[1].maxvalue < a)
            {
                puts("-1");
                continue;
            }
            printf("%d\n", Update(a, 1));
        }
    }
    return 0;
}

void BuildTree(int left, int right, int x)
{
    node[x].left = left;
    node[x].right = right;
    node[x].maxvalue = w;
    node[x].init();
    if (left == right) return;
    BuildTree(left, node[x].mid, LL(x));
    BuildTree(node[x].mid + 1, right, RR(x));
    return;
}

int Update(int a, int x)
{
    while (node[x].left != node[x].right)
    {
        x = node[LL(x)].maxvalue >= a ? LL(x) : RR(x);  //优先贴左边
    }
    node[x].maxvalue -= a;
    PushUp(x);
    return node[x].mid;
}

void PushUp(int x)
{
    while (x != 0)
    {
        x >>= 1;
        node[x].maxvalue = max(node[LL(x)].maxvalue, node[RR(x)].maxvalue);
    }
    return;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: