hdu 4614 Vases and Flowers 线段树

本文介绍了一个问题,涉及两种操作:一种是将指定数量的花放入盒子中,另一种是查询指定区间内的花的数量,并清空该区间内的盒子。通过使用线段树数据结构实现高效的区间操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接

一共n个盒子, 两种操作, 第一种是给出两个数x, y, 从第x个盒子开始放y朵花, 一个盒子只能放一朵, 如果某个盒子已经有了, 那么就跳过这个盒子放下面的盒子。 直到花放完了或者到了最后一个盒子。 输出放的第一朵花和最后一朵花的坐标, 如果一朵也没法放, 输出Can not put any one.

第二种操作, 给出l, r, 求l, r区间内有多少朵花, 输出, 并且将l, r内的盒子全部变空。

 

思路: 第二种操作比较简单, 区间查询然后区间置0就可以。

第一种操作, 首先查询[x, n]内一共有多少个盒子是空的, 如果全是满的, 直接输出Can not put any one.  设num为空盒子的数量, 那么显然y = min(y, num)。

接下来的问题就是找左右端点, 我是用的二分寻找左右端点, 具体的细节可以看代码。

#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <string>
#include <queue>
#include <stack>
#include <bitset>
using namespace std;
#define pb(x) push_back(x)
#define ll long long
#define mk(x, y) make_pair(x, y)
#define lson l, m, rt<<1
#define mem(a) memset(a, 0, sizeof(a))
#define rson m+1, r, rt<<1|1
#define mem1(a) memset(a, -1, sizeof(a))
#define mem2(a) memset(a, 0x3f, sizeof(a))
#define rep(i, n, a) for(int i = a; i<n; i++)
#define fi first
#define se second
typedef pair<int, int> pll;
const double PI = acos(-1.0);
const double eps = 1e-8;
const int mod = 1e9+7;
const int inf = 1061109567;
const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
const int maxn = 5e4+5;
int sum[maxn<<2], cnt[maxn<<2], n;
void pushUp(int rt) {
    sum[rt] = sum[rt<<1]+sum[rt<<1|1];
}
void pushDown(int rt, int m) {
    if(~cnt[rt]) {
        cnt[rt<<1] = cnt[rt<<1|1] = cnt[rt];
        sum[rt<<1] = cnt[rt]*(m-(m>>1));
        sum[rt<<1|1] = cnt[rt]*(m>>1);
        cnt[rt] = -1;
    }
}
void update(int L, int R, int l, int r, int rt, int val) {
    if(L<=l&&R>=r) {
        cnt[rt] = val;
        sum[rt] = val*(r-l+1);
        return ;
    }
    pushDown(rt, r-l+1);
    int m = l+r>>1;
    if(L<=m)
        update(L, R, lson, val);
    if(R>m)
        update(L, R, rson, val);
    pushUp(rt);
}
int query(int L, int R, int l, int r, int rt) {
    if(L<=l&&R>=r) {
        return sum[rt];
    }
    pushDown(rt, r-l+1);
    int m = l+r>>1, ret = 0;
    if(L<=m)
        ret += query(L, R, lson);
    if(R>m)
        ret += query(L, R, rson);
    return ret;
}
int bin(int l, int r, int val) {
    int ans, pos = l;
    while(l<=r) {
        int m = l+r>>1;
        if(m-pos+1-query(pos, m, 1, n, 1)>=val) {
            r = m-1;
            ans = m;
        } else {
            l = m+1;
        }
    }
    return ans;
}
int main()
{
    int t, m, x, y, sign;
    cin>>t;
    while(t--) {
        scanf("%d%d", &n, &m);
        mem1(cnt);
        mem(sum);
        while(m--) {
            scanf("%d%d%d", &sign, &x, &y);
            x++;
            if(sign == 1) {
                int num = query(x, n, 1, n, 1);
                if(num == n-x+1) {
                    puts("Can not put any one.");
                    continue;
                }
                y = min(y, n-x+1-num);
                int l = bin(x, n, 1);
                int r = bin(l, n, y);
                printf("%d %d\n", l-1, r-1);
                update(l, r, 1, n, 1, 1);
            } else {
                y++;
                printf("%d\n", query(x, y, 1, n, 1));
                update(x, y, 1, n, 1, 0);
            }
        }
        cout<<endl;
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/yohaha/p/5216081.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值