HDOJ 2795 - Billboard

Advanced Data Structures :: Segment Tree


Description

有一个h * w的框框(h行,每行w宽),你往里面放n块1 * wi矩形木板,每次都尽量往上面放(就是说,第一行放得下就不要放到第二行去)。

输入h、w、n和每块木板的wi,输出每块木板放入的位置(第几行),放不进去就输出-1。


Type

Advanced Data Structures :: Segment Tree


Analysis

我们把每行还可以放的宽度w当作一个数值,则一开始,一共有h个w宽的行可以放。

就可以用长度为h的线段树来储存这h个w,表示h个位置,都剩下w宽度可以放。

然后利用线段树的区间求最值功能,这样我们就可以快速地求得每个区间中能够放下多宽的木板。

这样时间复杂度就仅为O(n lg n)。

也许有同学会注意到,h高达10^9,完全没办法造这么大的线段树。

但是,我们还可以注意到,n只有20W,毫无疑问即使h高达10^9,也顶多会使用20W(最坏情况每层都放一个)。

因此只要开20W * 4的线段树数组即可。


Solution

// HDOJ 2795
// Billboard
// by A Code Rabbit

#include <algorithm>
#include <cstdio>
using namespace std;

#define LSon(x) ((x) << 1)
#define RSon(x) ((x) << 1 | 1)

const int MAXN = 200002;
const int ROOT = 1;

struct Seg{
    int w;
};

struct SegTree {
    Seg node[MAXN << 2];
    void Update(int pos) { node[pos].w = max(node[LSon(pos)].w, node[RSon(pos)].w); }
    void Build(int l, int r, int pos, int w) {
        node[pos].w = w;
        if (l == r) return;
        int m = l + r >> 1;
        Build(l, m, LSon(pos), w);
        Build(m + 1, r, RSon(pos), w);
        Update(pos);
    }
    int Remove(int l, int r, int pos, int x) {
        if (l == r) { node[pos].w -= x; return l; }
        int m = l + r >> 1;
        int res;
        if (x <= node[LSon(pos)].w) res = Remove(l, m, LSon(pos), x);
        else res = Remove(m + 1, r, RSon(pos), x);
        Update(pos);
        return res;
    }
};

int h, w, n;
int wi;

SegTree tree;

int main() {
    while (scanf("%d%d%d", &h, &w, &n) != EOF) {
        int top = min(h, n);
        tree.Build(1, top, ROOT, w);
        for (int i = 0; i < n; ++i) {
            scanf("%d", &wi);
            if (wi <= tree.node[ROOT].w)
                printf("%d\n", tree.Remove(1, top, ROOT, wi));
            else
                printf("-1\n");
        }
    }

    return 0;
}



你可能感兴趣的:(HDOJ 2795 - Billboard)