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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章