不看样例的话,很容易理解错题目。这里把h当做行,每个纸条都从上往下找有没有可以放的;如果可以放是直接拼接在之前纸条的后边。
那么这道题是怎么联想到线段树的呢?
把1-h这h行,看做h个数;初始大小都为w(代表每一行可以放多长的纸条)。对于每一个纸条长度x,都从上到下寻找是否存在一个数大于等于x。如果存在,输出这个数所在行号,并更新(减去x)。
那么我们只要维护一颗最大值线段树,修改一下查询的过程,就可以实现需求了。
需要注意的是虽然h规模很大,但其实没必要开那么大的线段树,因为n规模只有20万,所以会用到的行最多20w,按照这个大小开就可以了.
#include <bits/stdc++.h>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn=200000+10;
int tree[maxn<<2],h,w,n,width[maxn];
void PushUp(int rt)
{
tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
}
void build(int l,int r,int rt)
{
if(l==r)
{
tree[rt]=w;
return ;
}
int m=(l+r)>>1;
build(lson);
build(rson);
PushUp(rt);
}
int query(int x,int l,int r,int rt)//make sure every query,tree[rt] is no less than x
{
//recursion basis
if(l==r)
return l;
int m=(l+r)>>1;
if(tree[rt<<1]>=x)//go to lchild
return query(x,lson);
else
return query(x,rson);
}
void update(int p,int add,int l,int r,int rt)
{
if(l==r)
{
tree[rt]+=add;
return ;
}
int m=(l+r)>>1;
if(p<=m)
update(p,add,lson);
else
update(p,add,rson);
PushUp(rt);
}
int main(void)
{
int ans;
while(cin>>h>>w>>n)
{
build(1,n,1);
for(int i=0;i<n;i++)
{
scanf("%d",&width[i]);
if(width[i]>tree[1])//it is impossible to put up the poster
printf("-1\n");
else
{
ans=query(width[i],1,n,1);
if(ans<=h)
{
printf("%d\n",ans);
update(ans,-width[i],1,n,1);
}
else
printf("-1\n");
}
}
}
return 0;
}