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);
      }
    }    
  }
}

 

posted @ 2020-09-10 22:13  Kimyon  阅读(125)  评论(0编辑  收藏  举报