hdu2795-Billboard(线段树应用好题)
题意:有一块高*宽为h*w的牌子,n次操作输入一个val,每次操作贴一个1*val的牌子,贴法要求采用贪心策略:1.尽可能往上。2.在1的前提下尽可能往左。如果当前牌子不能贴上去就输出-1,否则输出当前牌子贴的位置的高度。
分析:线段树维护一下区间最大值,初始全部为设为w。考虑-1的情况,如果整个区间的最大值都不能满足val,那么说明任何一个地方都不能把这块牌子放上去,即输出-1,否则必然有至少一个点能把这块牌子放上。如何满足贪心策略1?线段树叶子结点为单点,其余为区间,自顶向下二分到单点就是答案,如果当前节点左下的值比val大,那么说明答案在左边,否则在右边。至于贪心策略2只需要每次更新最大值减去当前的val即可。
const int N = 2e5+10; int maxx[N<<2], h, w, n; void upd(int l, int r, int p, int i, int val) { if (l == r) {maxx[i] = val;return;} int mid = l + r >> 1; if (p <= mid) upd(l,mid,p,ls,val); else upd(mid+1,r,p,rs,val); maxx[i] = max(maxx[ls], maxx[rs]); } void run() { while (~scanf("%lld%lld%lld",&h,&w,&n)) { int e = min(h, n); for (int i = 1; i <= e; i++) upd(1,e,i,1,w); for (int i = 1, tmp; i <= n; i++) { tmp = rd(); if (tmp > maxx[1]) puts("-1"); else { int i = 1, l = 1, r = e; while (l < r) { int mid = l + r >> 1; if (maxx[ls] >= tmp) i = (ls), r = mid; else i = (rs), l = mid+1; } printf("%lld\n",l); upd(1,e,l,1,maxx[i]-tmp); } } } }