大意:给一个h*w的公告板,然后给出多个1*wi的广告往板子上贴,如果有空间尽量往上一行贴,输出行数,无法贴上,则输出-1;
思路很巧妙,将公告板每一行映射到线段树的一个叶子节点,每个节点保存该区间内剩余可用长度最大值。每次在能满足的区间里尽量向左查询,查询到立即修改,query和update合并(写线段树注意别漏了pushup)。如果没有满足的任何一行(即tree[1] < wi, tree[1]为最大值),则返回-1。注意建树时行数取小值。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 2e5 + 10;
int tree[maxn<<2];
int h, w, n;
void pushup(int root)
{
tree[root] = max(tree[root<<1], tree[root<<1|1]);
}
void build(int cur, int b, int e)
{
if(b == e)
tree[cur] = w;
else
{
int mid = (b + e)>>1;
build(cur<<1, b, mid);
build(cur<<1|1, mid + 1, e);
pushup(cur);
}
}
int query(int cur, int b, int e, int x)
{
//printf("%d %d %d\n", cur, b, e);
if(b == e)
{
if(tree[cur] >= x)
{
tree[cur] -= x;
return b;
}
else
{
return -1;
}
}
else
{
int mid = b + e >> 1;
int ans;
if(x <= tree[cur << 1])
ans = query(cur << 1, b, mid, x);
else
ans = query(cur << 1|1, mid + 1, e, x);
pushup(cur);
return ans;
}
}
int main()
{
while(scanf("%d%d%d", &h, &w, &n) != EOF)
{
h = min(h, n);
build(1, 1, h);
int x;
for(int i = 0; i < n; i++)
{
scanf("%d", &x);
if(tree[1] < x)
printf("-1\n");
else
printf("%d\n", query(1, 1, h, x));
}
}
return 0;
}