hdu4614 Vases and Flowers (线段树)

题目链接:点击链接

题意:

有标号从0到n-1的n个花瓶,每个花瓶只能放一朵花。现在有两种操作,操作一,从第a个花瓶开始,放b朵花进入花瓶,如果能放,输出能放的最左边的位置,和最右边的位置,如果不能放,输出不能放。操作二,将花瓶a到花瓶b这个区间内的花全部丢弃。

思路:

维护区间内花的数量sumv[rt],区间内最左边空花瓶的位置为L[rt],最右边位置为R[rt]。
设花瓶空为0,有花为1,操作一则是要求如何快速将区间内的0改成1。
我们维护了区间内花的总数sumv[rt],先是和以往的update函数一样,确定区间范围,如果当前区间内空花瓶的数量int cha = (r-l+1)-sumv[rt]小于等于待放花数b时,b -= cha。如果cha大于b,我们递归的先放左边,再放右边。

操作二是区间置相同值。

总结:

这道题思路出来很快,但是实现一直有问题,后来发现是没有维护L[]和R[]的值…怕是石乐志。
仍旧wa了。
对拍发现了一个难以理解的细节,build函数明明会把L[], R[], sumv[], setv[]都初始化好,但是我写的程序,上一个样例影响到了当前样例,按理说不会访问到上一个样例残留的数据。
原来setv[]没有初始化好…

代码:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>

using namespace std;

const int maxn = 50000 + 100;
const int INF = 0x3f3f3f3f;
int _st, _ed, _sum, _now, t, n, m, opt, aa, bb;  

int L[maxn<<2], R[maxn<<2];
int setv[maxn<<2], sumv[maxn<<2]; // sumv is the quantity of flowers

void pushup(int rt){
    setv[rt] = -1;
    sumv[rt] = sumv[rt<<1] + sumv[rt<<1|1];
    L[rt] = min(L[rt<<1], L[rt<<1|1]);
    R[rt] = max(R[rt<<1], R[rt<<1|1]);
}

void pushdown(int l, int r, int rt, int len){
    if(setv[rt]!=-1){
        setv[rt<<1] = setv[rt<<1|1] = setv[rt];
        sumv[rt<<1] = (len - len/2) * setv[rt];
        sumv[rt<<1|1] = (len/2) * setv[rt];
        if(setv[rt]==1){
            L[rt<<1] = L[rt<<1|1] = INF;
            R[rt<<1] = R[rt<<1|1] = -INF; 
        }
        else{
            int mid = (l+r)>>1;
            L[rt<<1] = l;
            R[rt<<1] = mid;
            L[rt<<1|1] = mid+1;
            R[rt<<1|1] = r;
        }
        setv[rt] = -1;
    }
}

void build(int rt, int l, int r){
    if(l==r){
        L[rt] = R[rt] = l;
        sumv[rt] = 0;
        setv[rt] = -1;
    }
    else{
        int mid = (l+r)>>1;
        build(rt<<1, l, mid);
        build(rt<<1|1, mid+1, r);
        pushup(rt);
    }
}

void Set(int rt, int a, int b, int l, int r){
    if(_now == 0) return ;
    if(a<=l && r<=b){
        if(sumv[rt] == (r-l+1)) return;   // full of flowers
        if(_now <= 0) return;             // all flowers are put into vases before current one
        int cha = r-l+1 - sumv[rt];
        if(cha > _now){                
            pushdown(l, r, rt, r-l+1);
            int mid = (l+r)>>1;
            Set(rt<<1, a, b, l, mid);
            Set(rt<<1|1, a, b, mid+1, r);
            pushup(rt);
        }
        else{
            _now -= cha;
            _st = min(_st, L[rt]);
            _ed = max(_ed, R[rt]);
            setv[rt] = 1;
            sumv[rt] = r-l+1;
            L[rt] = INF;
            R[rt] = -INF;
        }
    }
    else{
        pushdown(l, r, rt, r-l+1);
        int mid = (l+r)>>1;
        if(a<=mid) Set(rt<<1, a, b, l, mid);
        if(mid<b) Set(rt<<1|1, a, b, mid+1, r);
        pushup(rt);
    }
}


void Discard(int rt, int a, int b, int l, int r){
    if(a<=l && r<=b){
        _sum += sumv[rt];
        sumv[rt] = 0;
        setv[rt] = 0;
        L[rt] = l;
        R[rt] = r;
    }
    else{
        pushdown(l, r, rt, r-l+1);
        int mid = (l+r)>>1;
        if(a<=mid) Discard(rt<<1, a, b, l, mid);
        if(mid<b) Discard(rt<<1|1, a, b, mid+1, r);
        pushup(rt);
    }   
}

int main(){
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    scanf("%d", &t);
    while(t--){
        scanf("%d%d", &n, &m);
        // memset(setv, -1, sizeof(setv));
        // memset(sumv,  0, sizeof(sumv));
        build(1, 1, n);
        for(int i=0; i<m; ++i){
            scanf("%d%d%d", &opt, &aa, &bb);
            if(opt==1){
                _st = INF; _ed = -INF; _now = bb;
                Set(1, aa+1, n, 1, n);
                if(_now == bb){
                    printf("Can not put any one.\n");
                }
                else{
                    printf("%d %d\n", _st-1, _ed-1);
                }
            }
            if(opt==2){
                _sum = 0;
                Discard(1, aa+1, bb+1, 1, n);
                printf("%d\n", _sum);
            }
        }
        printf("\n");
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值