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