HDU4614-二分+线段树

(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦

题意:传送门

 原题目描述在最下面。
 两种操作,1:把 b b 朵花,从 a a 开始一个位置放一瓶,若该位置有花则跳过,每次输出插入花朵的起点的终点。若没有位置可以插花,则输出 Cannotputanyone. C a n n o t p u t a n y o n e . 。2:把 a a b b 位置的花瓶清空,并输出之前这个区间内有多少朵花。

思路:

lazy=1 l a z y = 1 表示子区间内所有花瓶都可以插花, lazy=0 l a z y = 0 表示区间内所有花瓶都被插满了,初始化 lazy=1 l a z y = − 1
sum s u m 表示区间内可以插花的数量。
 这样定义就很好写 pushdown p u s h d o w n pushup p u s h u p 了。

 这题麻烦在于需要二分。对于操作1,先二分找出第一个可以插花的位置,若找不到则输出那句话。然后要二分终点的位置,这时还要区分这个区间能不能插满 b b 朵花。若可以插满则直接二分插入满 b b 朵花的终点就好,若不能插满则二分最后一个可插的位置。

AC代码:

#include
#include
#include
#include
#include
#include
#define lson rt<<1
#define rson rt<<1|1
#define lowbit(x) (x)&(-(x))
#define all(x) (x).begin(),(x).end()
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int N = (int)1e5 +107;
int n, m;
struct lp{
  int l, r;
  int lazy;//lazy==1表示下面都可以插,lazy==0表示都被插了,lazy==-1表示未被更新
  int sum;//可插的数量,叶子节点为被插就是1
}cw[N<<2];
inline void push_up(int rt){
  cw[rt].sum = cw[lson].sum+cw[rson].sum;
}
void build(int l,int r,int rt){
  int mid = (l + r)>>1;
  cw[rt].l=l;cw[rt].r=r;
  cw[rt].lazy=-1;
  if(l==r){
    cw[rt].sum = 1;
    return;
  }
  build(l,mid,lson);build(mid+1,r,rson);
  push_up(rt);
}
void push_down(int rt){
  if(cw[rt].lazy!=-1){
    cw[lson].lazy=cw[rson].lazy=cw[rt].lazy;
    cw[lson].sum=(cw[lson].r-cw[lson].l+1)*cw[rt].lazy;
    cw[rson].sum=(cw[rson].r-cw[rson].l+1)*cw[rt].lazy;
    cw[rt].lazy=-1;
  }
}
void update(int L,int R,int c,int rt){
  int l=cw[rt].l,r=cw[rt].r,mid=(l+r)>>1;
  if(L<=l&&r<=R){
    cw[rt].lazy = c;
    cw[rt].sum = c*(r-l+1);
    return;
  }
  if(cw[rt].l==cw[rt].r)return;
  push_down(rt);
  if(L>mid)update(L,R,c,rson);
  else if(R<=mid)update(L,R,c,lson);
  else{
    update(L,mid,c,lson),update(mid+1,R,c,rson);
  }
  push_up(rt);
}
int query(int L,int R,int rt){
  int l=cw[rt].l,r=cw[rt].r,mid=(l+r)>>1;
  if(L<=l&&r<=R){
    return cw[rt].sum;
  }
  if(cw[rt].l==cw[rt].r)return 0;
  push_down(rt);
  int sum = 0;
  if(L>mid)sum = query(L,R,rson);
  else if(R<=mid)sum = query(L,R,lson);
  else{
    sum = query(L,mid,lson)+query(mid+1,R,rson);
  }
  return sum;
}
int main(){
  int tim;
  scanf("%d",&tim);
  while(tim--){
    scanf("%d%d",&n,&m);
    build(1,n,1);
    int op,x,y;
    while(m--){
      scanf("%d%d%d",&op,&x,&y);
      if(op==1){
        ++x;
        int l = x,r = n,st = -1,ed = n,mid;
        while(l<=r){
          mid = (l+r)>>1;
          if(query(x,mid,1)>=1){
            st=mid;
            r=mid-1;
          }else{
            l=mid+1;
          }
        }
        if(st==-1){
          printf("Can not put any one.\n");
          continue;
        }
        l = st,r = n;
        if(query(l,r,1)>=y){
          while(l<=r){
            mid = (l+r)>>1;
            if(query(st,mid,1)>=y){
              ed = mid;
              r = mid-1;
            }else{
              l = mid+1;
            }
          }
        }else{
          while(l<=r){
            mid = (l+r)>>1;
            if(query(mid,n,1)>=1){
              l = mid+1;
              ed = mid;
            }else{
              r = mid-1;
            }
          }
        }
        printf("%d %d\n", st-1,ed-1);
        update(st,ed,0,1);
      }else{
        printf("%d\n", y-x+1- query(x+1,y+1,1));
        update(x+1,y+1,1,1);
      }
    }
    puts("");
  }
  return 0;
}


原题目描述:

HDU4614-二分+线段树_第1张图片

你可能感兴趣的:(线段树,ACM-二分-三分,ACM算法之旅)