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;
}