题意:有一个板,h行,每行w长度的位置。每次往上面贴一张海报,长度为1*wi .
每次贴的时候,需要找到最上面的,可以容纳的空间,并且靠边贴。
转换一下,就是有一个数组,开始都为w,每次给一个数x,就数组中找到 >=x 的数中最小的坐标,并把对应这个坐标的数 - x。
用线段树来储存区间最大值。查找时,递归查询,若左边的区间的最大值大于x,则要找的坐标在左边,否则在右边。
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #define maxn 200010 using namespace std; int h,w,n,k; int H[maxn<<2]; void PushUp(int rt){ H[rt]=max(H[rt<<1],H[rt<<1|1]); } void build(int l,int r ,int rt){ if(l==r){ H[rt]=w; return; } int m=(l+r)>>1; build(l,m,rt<<1); build(m+1,r,rt<<1|1); PushUp(rt); } void ADD(int X,int C,int l,int r,int rt){ if(l==r){ H[rt]+=C; return; } int m=(l+r)>>1; if(X <= m) ADD(X,C,l,m,rt<<1); if(X > m) ADD(X,C,m+1,r,rt<<1|1); PushUp(rt); } int Query(int X,int l,int r,int rt){ if(l==r){ return l; } int m=(l+r)>>1; if(H[rt<<1]>=X) return Query(X,l,m,rt<<1); else return Query(X,m+1,r,rt<<1|1); } int main(void) { while(~scanf("%d%d%d",&h,&w,&n)){ if(h>maxn) h=200001; build(1,h,1); for(int i=0;i<n;++i){ scanf("%d",&k); if(H[1]<k){ printf("-1\n"); } else{ int I=Query(k,1,h,1); printf("%d\n",I); ADD(I,-k,1,h,1); } } } return 0; }