题目链接:[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; }