Vases and Flowers HDU - 4614 (线段树 区间修改+二分查找)

1. 从a开始在空花瓶放b枝花,花放完或第N-1个花瓶放完为止 输出放花的第一个和最后一个位置

2. 将[a,b]的花都扔掉 输出扔了多少枝花

思路:

线段树维护[0,N-1]空花瓶数v

求a之前有多少空花瓶V(查[0,N-1]空花瓶数 - [a,N-1]空花瓶数)

二分查找放花的第一个和最后一个位置(

先求出可以放多少枝花,min ( [a,N-1]的空花瓶数 , b )

然后

二分查找第V+1个空瓶的位置 是第一个放花的位置

二分查找第V+b个空瓶的位置 是最后一个放花的位置)

因为维护的是区间空花瓶数的和 从[0,N-1]是递增的 仔细体会!

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define lson (pos<<1)
#define rson (pos<<1|1)
const int maxn=55555;
struct Node{
    int l,r;
    int v,col;//v 空花瓶数, col lazy标记
}node[maxn<<2];
int N,M;
void pushup(int pos){
    node[pos].v=node[lson].v+node[rson].v;
}
void pushdown(int pos){
    if(node[pos].col>=0){//有被标记
        node[lson].col=node[pos].col; node[rson].col=node[pos].col;
        node[lson].v=(node[lson].r-node[lson].l+1)*node[pos].col;
        node[rson].v=(node[rson].r-node[rson].l+1)*node[pos].col;
        node[pos].col=-1;
    }
}
void Build(int L,int R,int pos){
    node[pos].l=L; node[pos].r=R; node[pos].col=-1;//初始化
    if(L==R){ node[pos].v=1; return;}//叶子 递归边界 
    int m=(L+R)>>1;
    Build(L,m,lson); Build(m+1,R,rson); pushup(pos);//回溯前由现在的节点更新父节点
}
void UpDate(int L,int R,int pos,int value){
    if(L <= node[pos].l && node[pos].r <= R){
        node[pos].v = (node[pos].r - node[pos].l + 1) * value;
        node[pos].col = value;
        return;
    }
    pushdown(pos);
    int m = (node[pos].l + node[pos].r) >> 1;
    if(L<=m) UpDate(L,R,lson,value);
    if(R>m) UpDate(L,R,rson,value);
    pushup(pos);
}
int Query_sum(int L,int R,int pos){//空花瓶数
    if(L<=node[pos].l&&node[pos].r<=R) return node[pos].v;
    pushdown(pos);//递归前下推标记
    int m=(node[pos].l+node[pos].r)>>1;
    int ret=0;
    if(L<=m) ret+=Query_sum(L,R,lson); //都是L、R
    if(R>m) ret+=Query_sum(L,R,rson);
    pushup(pos);
    return ret;
}
void Search(int value,int pos,int &p){
    if(node[pos].l==node[pos].r){ p=node[pos].l; return; }
    pushdown(pos);
    int m=(node[pos].l+node[pos].r)>>1;
    if(node[lson].v>=value) Search(value,lson,p);
    else Search(value-node[lson].v,rson,p);
    pushup(pos);
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&N,&M);
        Build(0,N-1,1);
        int op,a,b;
        for(int i=0;i<M;++i){
            scanf("%d%d%d",&op,&a,&b);
            if(op==1){//修改 放花
                int sum=Query_sum(0,N-1,1);
                int k1=Query_sum(a,N - 1,1);//[a,N-1]一共有k1个空花瓶
                int v=sum-k1;//a之前有v个空花瓶 修改操作起:第v+1个空花瓶
                int p,q;
                if(k1==0){ printf("Can not put any one.\n"); continue;}
                if(k1 < b) b = k1;//空花瓶数k1不足b个 则最多只能插k1朵花
                Search(v + 1,1,p);//查第v+1个空花瓶在哪
                Search(v + b,1,q);//查第v+b个空花瓶在哪 (修改操作止:第v+b个空花瓶 )
                UpDate(p,q,1,0);//区间[p,q]改为0(空花瓶1 非空为0)
                printf("%d %d\n",p,q);
            } else if(op == 2){
                int value = Query_sum(a,b,1);//查[a,b]区间空花瓶数
                UpDate(a,b,1,1);//区间[p,q]改为0(空花瓶1 非空为0)
                printf("%d\n",b - a + 1 - value);
            }
        }
        printf("\n");
    }
    return 0;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值