hdu 4614(线段树)

题目链接

挺基础的一个线段树题目,两种操作, 第二种就是区间和, 第一种的话起始下标也很容易得到, 主要是终点下标需要思考一下, 我的做法是记录下当前剩余多少花还没放, 然后找到第一个剩余花小于当前区间总空位的个数的区间, 然后根据左子区间的剩余情况再递归直到叶子节点, 线段树每个节点维护三个统计量空位的个数第一个空位最后一个空位, 以及一个lazy标记。

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

using namespace std;

const int N = 50005;

#define lch rt << 1, L, mid
#define rch rt << 1 | 1, mid + 1, R

struct SegmentTree {
	int idx[N << 2], cnt[N << 2], lazy[N << 2], last[N << 2];
	int n, st, ed, rem;

	void init(int n) {
		this->n = n;
		build(1, 0, n - 1);
	}
	
	void build(int rt, int L, int R) {
		idx[rt] = L, lazy[rt] = -1, cnt[rt] = R - L + 1, last[rt] = R;
		if (L == R) {
			return;
		}
		int mid = L + R >> 1;
		build(lch);
		build(rch);
	}

	inline void push_up(int rt) {
		cnt[rt] = cnt[rt << 1 | 1] + cnt[rt << 1];

		if (cnt[rt << 1] > 0)
			idx[rt] = idx[rt << 1];
		else if (cnt[rt << 1 | 1] > 0)
			idx[rt] = idx[rt << 1 | 1];
		else
			idx[rt] = -1;

		if (cnt[rt << 1 | 1] > 0)
			last[rt] = last[rt << 1 | 1];
		else if (cnt[rt << 1] > 0)
			last[rt] = last[rt << 1];
		else
			last[rt] = -1;
	}

	inline void push_down(int rt, int L, int R) {
		if (lazy[rt] != -1) {
			int mid = L + R >> 1;
			if (lazy[rt]) {
				cnt[rt << 1] = 0;
				cnt[rt << 1 | 1] = 0;
				idx[rt << 1] = -1;
				idx[rt << 1 | 1] = -1;
				lazy[rt << 1] = lazy[rt << 1 | 1] = 1;
				last[rt << 1] = last[rt << 1 | 1] = -1;
			}
			else {
				cnt[rt << 1] = mid - L + 1;
				cnt[rt << 1 | 1] = R - mid;
				idx[rt << 1]  = L;
				idx[rt << 1 | 1] = mid + 1;
				lazy[rt << 1] = lazy[rt << 1 | 1] = 0;
				last[rt << 1] = mid, last[rt << 1 | 1] = R;
			}
			lazy[rt] = -1;
		}	
	}

	int update(int rt, int L, int R, int l, int r) {
		if (l <= L && R <= r) {
			lazy[rt] = 0;
			int tmp = R - L + 1 - cnt[rt];
			idx[rt] = L, cnt[rt] = R - L + 1;
			last[rt] = R;
			return tmp;
		}
		int mid = L + R >> 1;
		push_down(rt, L, R);
		int res = 0;
		if (l <= mid)
			res += update(lch, l, r);
		if (r > mid)
	       		res += update(rch, l, r);
		push_up(rt);
		return res;
	}

	int gao(int rt, int L, int R) {
		if (L == R) {
			rem = 0;
			cnt[rt] = 0, idx[rt] = -1, last[rt] = -1;
			return L;
		}

		int mid = L + R >> 1;
		push_down(rt, L, R);
		int res; 
		if (cnt[rt << 1] >= rem) 
			res = gao(lch);
		else {
			rem -= cnt[rt << 1];
			cnt[rt << 1] = 0, idx[rt << 1] = -1, last[rt] = -1;
			lazy[rt << 1] = 1;
			res = gao(rch);
		}
		push_up(rt);
		return res;
	}
	
	void modify(int rt, int L, int R, int l) {
		if (L >= l) {

			if (rem <= 0 || cnt[rt] == 0) return;
			
			if (st == -1 && cnt[rt] > 0) {
				st = idx[rt];
			}

			if (R == n - 1) {
				if (rem > cnt[rt])
					rem = cnt[rt];
				
				if (cnt[rt])
					ed = gao(rt, L, R);
			}
			else {
				if (rem > cnt[rt]) {
					rem -= cnt[rt];
					cnt[rt] = 0, idx[rt] = -1;
					lazy[rt] = 1;
					ed = last[rt];
					last[rt] = -1;
				}
				else {
					if (cnt[rt])
						ed = gao(rt, L, R);	
				}
			}

			return;
		}
		int mid = L + R >> 1;
		push_down(rt, L, R);
		if (l <= mid)
			modify(lch, l);
		if (R >= l)
			modify(rch, l);
		push_up(rt);	
	}

	void op1(int p, int c) {
		rem = c, st = -1, ed = -1;
		modify(1, 0, n - 1, p);
	}

	int op2(int l, int r) {
		return update(1, 0, n - 1, l, r);	
	}
			
}T;

int main() {
	int test, n, m, op, l, r, p, f;

	scanf("%d", &test);

	while (test--) {
		scanf("%d%d", &n, &m);
		T.init(n);
		for (int i = 0; i < m; i++) {
			scanf("%d", &op);
			if (op == 1) {
				scanf("%d%d", &p, &f);
				T.op1(p, f);
				if (T.st == -1) 
					puts("Can not put any one.");
				else {
					printf("%d %d\n", T.st, T.ed);			
				}
			}
			else {
				scanf("%d%d", &l, &r);
				printf("%d\n", T.op2(l, r));
			}
		}

		puts("");
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值