[HDU 2795]Billboard[线段树]

题目链接:[HDU 2795]Billboard[线段树]

题意分析:

有一个高度为h,宽度为w的广告板,给出n个海报,每个海报高度1,宽度x。问能否贴到广告板上,能输出贴到的行,否则输出-1。每张海报必须贴到能贴部分的最左上角。

解题思路:

用线段树区间存:区间中还能贴的最大宽度;每次查询整个区间,满足就继续,否则返回,当l == r时说明查询到了最满足的行,然后进行更新。

个人感受:

意淫了一下,然后第一发是用h当区间最高点,re了。然后改成h = min(h, n)(海报如果贴满顶多贴n行)。顺利过了,自己都觉得神奇,难得意淫。

具体代码如下:

#include<iostream>
#include<cstdio>
#define root 1, h, 1
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
using namespace std;

const int MAXN = 2e5 + 111;

int lef[MAXN << 2], ans, h, w, n;

void push_up(int rt)
{
    lef[rt] = max(lef[rt << 1], lef[rt << 1 | 1]);
}

void update(int x, int val, int l, int r, int rt)
{
    if (l == r)
    {
        lef[rt] -= val;
        return;
    }
    int m = (l + r) >> 1;
    if (x <= m) update(x, val, lson);
    else update(x, val, rson);
    push_up(rt);
}

bool query(int val, int l, int r, int rt)
{
    if (lef[rt] < val) return 0;
    if (l == r)
    {
        ans = l;
        update(ans, val, root);
        return 1;
    }
    int m = (l + r) >> 1;
    if (query(val, lson)) return 1;
    if (query(val, rson)) return 1;
    return 0;
}

int main()
{
    while (~scanf("%d%d%d", &h, &w, &n))
    {
        h = min(h, n);
        for (int i = 1; i <= n << 2; ++i) lef[i] = w;
        int x;
        for (int i = 0; i < n; ++i)
        {
            scanf("%d", &x);
            if (query(x, root)) printf("%d\n", ans);
            else puts("-1");
        }
    }
    return 0;
}


你可能感兴趣的:(线段树)