1. 程式人生 > 實用技巧 >hdu2795-Billboard(線段樹應用好題)

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

int find(int l, int
r, int val, int &change) { int i = 1; while (l < r) { int mid = l + r >> 1; if (maxx[ls] >= val) i = (ls), r = mid; else i = (rs), l = mid+1; change = maxx[i]; } return l; } 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 now; int pos = find(1,e,tmp,now); printf("%lld\n",pos); upd(1,e,pos,1,now-tmp); } } } }