题意分析:
有一个高度为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;
}