hdu 4614(区间更新)

这里写代码片题意:有n个花瓶编号从0到n-1,初始花瓶都是空的,然后有两个操作,1 a b表示从位置a开始往后面找b(不够b个也可以)个空花瓶插花,输出插花的首位置和末位置,2 a b表示输出区间[a,b]有多少个花,并且把这个区间内所有花都拿走。
题解:很容易想到用线段树维护区间内有多少个空花瓶,然后操作2可以直接用普通的区间查询和区间修改,操作1可以看作先查询前a-1个花瓶有num个是空的,然后查询第num+1和第num+b个空花瓶的位置,这个查询也可以用线段树查询或二分查找来写。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 50005;
int n, q, tree[N << 2], flag[N << 2];

void pushup(int k) {
    tree[k] = tree[k * 2] + tree[k * 2 + 1];
}

void pushdown(int k, int left, int right) {
    if (flag[k] == 1) {
        flag[k * 2] = flag[k * 2 + 1] = flag[k];
        tree[k * 2] = tree[k * 2 + 1] = 0;
        flag[k] = 0;
    }
    else if (flag[k] == 2) {
        int mid = (left + right) / 2;
        flag[k * 2] = flag[k * 2 + 1] = flag[k];
        tree[k * 2] = mid - left + 1;
        tree[k * 2 + 1] = right - mid;
        flag[k] = 0;
    }
}

void build(int k, int left, int right) {
    flag[k] = 0;
    tree[k] = right - left + 1;
    if (left != right) {
        int mid = (left + right) / 2;
        build(k * 2, left, mid);
        build(k * 2 + 1, mid + 1, right);
    }
}

void modify(int k, int left, int right, int l, int r, int x) {
    if (l <= left && right <= r) {
        flag[k] = x;
        if (x == 1) tree[k] = 0;
        else tree[k] = right - left + 1;
        return;
    }
    pushdown(k, left, right);
    int mid = (left + right) / 2;
    if (l <= mid)
        modify(k * 2, left, mid, l, r, x);
    if (r > mid)
        modify(k * 2 + 1, mid + 1, right, l, r, x);
    pushup(k);
}

int query(int k, int left, int right, int l, int r) {
    if (l <= left && right <= r)
        return tree[k];
    pushdown(k, left, right);
    int mid = (left + right) / 2, res = 0;
    if (l <= mid)
        res += query(k * 2, left, mid, l, r);
    if (r > mid)
        res += query(k * 2 + 1, mid + 1, right, l, r);
    pushup(k);
    return res;
}

int Find(int k, int left, int right, int l, int r, int pos) {
    if (left == right)
        return left;
    pushdown(k, left, right);
    int mid = (left + right) / 2, temp;
    if (r <= mid)
        temp = Find(k * 2, left, mid, l, r, pos);
    else if (l > mid)
        temp = Find(k * 2 + 1, mid + 1, right, l, r, pos);
    else {
        if (pos <= tree[k * 2])
            temp = Find(k * 2, left, mid, l, r, pos);
        else
            temp = Find(k * 2 + 1, mid + 1, right, l, r, pos - tree[k * 2]);
    }
    pushup(k);
    return temp;
}

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        scanf("%d%d", &n, &q);
        build(1, 0, n - 1);
        int op, l, x;
        while (q--) {
            scanf("%d%d%d", &op, &l, &x);
            if (op == 1) {
                int temp = query(1, 0, n - 1, l, n - 1);
                if (!temp) {
                    printf("Can not put any one.\n");
                    continue;
                }
                else if (temp <= x)
                    x = temp;
                int num = 0;
                if (l >= 1)
                    num = query(1, 0, n - 1, 0, l - 1);
                int st = Find(1, 0, n - 1, 0, n - 1, num + 1);
                int en = Find(1, 0, n - 1, 0, n - 1, num + x);
                printf("%d %d\n", st, en);
                modify(1, 0, n - 1, st, en, 1);
            } else {
                printf("%d\n", x - l + 1 - query(1, 0, n - 1, l, x));
                modify(1, 0, n - 1, l, x, 2);
            }
        }
        printf("\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值