hdu 4614 Vases and Flowers 线段树

题目链接

一共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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值