题目大意:一个h*w的公告牌,要在其上贴公告。 输入的是1*wi的w值,这些是公告的尺寸接下来要满足的条件有:1、尽量往上,同一高度尽量靠左。2、求第n个广告所在的行数。3、没有合适的位置贴了则输出-1。
用线段树实现,节点存的是每一行剩余的空位,查找用的是二分的思想,每次在区间里查找第一个大于等于val值的位置。
先查左子区间是否存在大于等于val值,如果是则进入左子区间查询,否则,再去判断右区间
一直二分直到l==r,返回l下标即是 第一个大于等于val值的位置。
#include <cstdio> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <queue> #include <map> #include <set> #include <vector> #include <iostream> using namespace std; const long long maxn = 200005; struct tree { __int64 st_max[maxn*4]; void init() { memset(st_max,0,sizeof(st_max)); } void pushup(__int64 rt) { st_max[rt]=max(st_max[rt<<1],st_max[rt<<1|1]); } void update(__int64 l,__int64 r,__int64 rt,__int64 num,__int64 val) { if (l==r&&r==num) { st_max[rt]+=val; return ; } __int64 m=(l+r)>>1; if (num<=m) update(l,m,rt<<1,num,val); else update(m+1,r,rt<<1|1,num,val); pushup(rt); } __int64 query(__int64 val,__int64 l,__int64 r,__int64 rt) //查询大于等于val的第一个位置 { if (r==l) { return l; } __int64 mid=(l+r)>>1; if (st_max[rt<<1]>=val) return query(val,l,mid,rt<<1); if (st_max[rt<<1|1]>=val) return query(val,mid+1,r,rt<<1|1); return -1; } }; tree tp; int main( ) { __int64 i; __int64 x; __int64 n,h,w; __int64 cun=0; while(scanf("%I64d %I64d %I64d",&h,&w,&n)!=EOF) { tp.init(); if (h>n) h=n; for (i=1; i<=h; i++) tp.update(1,h,1,i,w); for (i=1; i<=n; i++) { scanf("%I64d",&x); __int64 ret=tp.query(x,1,h,1); if (x>tp.st_max[1]) printf("-1\n"); else { printf("%I64d\n",ret); tp.update(1,h,1,ret,-x); } } } return 0; }