传送门:点击打开链接
题目大意:
貌似是著名的线段树经典问题贴海报。
给定一个高H,宽W的黑板,然后每次要贴一张高度为1,长度为X的海报,要求尽量往上贴,并且同一行有海报的情况就贴在上一个海报右边,不能和其他海报重叠,也不能超过黑板的宽度。
每次询问给定一张海报,问贴在了哪一行,如果没有可行方案 就输出-1。
解题思路:
由于是每次尽量贴在了这一行的最左边,那么其实就是每一行一开始都有W个位置是可以贴海报的,如果要贴一张海报的话。对应的这个位置的值也就减少了X。
于是乎就可以用线段树搞了,记录一个最大值。如果一个线段的左区间的最大值是满足>=X的 那么就继续查左区间 不然一定在右区间。
不能贴的情况直接查询根节点就好了。
#include <cstdio>
#include <algorithm>
using namespace std;
#define maxn 200010
struct Node
{
int l,r,max;
}tree[maxn<<2];
int n,w,h;
inline void pushup(int id)
{
tree[id].max = max(tree[id<<1].max,tree[id<<1|1].max);
}
void build(int id,int l,int r)
{
tree[id].l = l;
tree[id].r = r;
if(l == r)
{
tree[id].max = w;
return ;
}
int mid = (l+r)>>1;
build(id<<1,l,mid);
build(id<<1|1,mid+1,r);
pushup(id);
}
int query(int id,int x)
{
if(tree[id].l == tree[id].r)
{
tree[id].max -= x;
return tree[id].l;
}
int res = 0;
if(tree[id<<1].max >= x)
res = query(id<<1,x);
else
res = query(id<<1|1,x);
pushup(id);
return res;
}
int main()
{
while(scanf("%d %d %d",&h,&w,&n) != EOF)
{
build(1,1,min(h,n));
while(n--)
{
int x;
scanf("%d",&x);
if(tree[1].max < x)
printf("-1\n");
else
printf("%d\n",query(1,x));
}
}
return 0;
}