BZOJ 4631: 踩气球

线段树上每个节点开个vector,表示包含当前区间的熊孩子的编号
当一个区间的值变为 \(0\) 时遍历这个vector,对熊孩子的权值减去当前区间原始权值和
当熊孩子的权值变为 \(0\) 时答案加一
vector总共只有 \(O(m \log n)\) 个元素,最多会被遍历一次
所以复杂度还是 \(O(n\log n)\)

#include <bits/stdc++.h>
#define lp p << 1
#define rp p << 1 | 1
#define mid ((l + r) >> 1)

namespace IO {
	void read() {}
	template<class T, class ... T2>
	inline void read(T &x, T2 &... oth) {
		x = 0; T f = 1; char ch = getchar();
		while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
		while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
		x *= f;
		read(oth...);
	}
}

const int N = 1e5 + 7;
int n, m;
int tree[N << 2], val[N << 2], a[N];
std::vector<int> vec[N << 2];

void build(int p, int l, int r) {
	if (l == r) {
		IO::read(tree[p]);
		val[p] = tree[p];
		return;
	}
	build(lp, l, mid);
	build(rp, mid + 1, r);
	tree[p] = tree[lp] + tree[rp];
	val[p] = val[lp] + val[rp];
}

void update(int p, int l, int r, int x, int y, int id) {
	if (x <= l && y >= r) {
		vec[p].push_back(id);
		a[id] += val[p];
		return;
	}
	if (x <= mid) update(lp, l, mid, x, y, id);
	if (y > mid) update(rp, mid + 1, r, x, y, id);
}

int ans;

void update(int p, int l, int r, int pos) {
	if (l == r) {
		tree[p]--;
		if (!tree[p]) {
			for (int i = 0; i < vec[p].size(); i++) {
				int id = vec[p][i];
				a[id] -= val[p];
				if (!a[id]) ans++;
			}
			vec[p].clear();
		}
		return;
	}
	if (pos <= mid) update(lp, l, mid, pos);
	else update(rp, mid + 1, r, pos);
	tree[p] = tree[lp] + tree[rp];
	if (!tree[p]) {
		for (int i = 0; i < vec[p].size(); i++) {
			int id = vec[p][i];
			a[id] -= val[p];
			if (!a[id]) ans++;
		}
		vec[p].clear();
	}
}

int main() {
	IO::read(n, m);
	build(1, 1, n);
	for (int i = 1; i <= m; i++) {
		int l, r;
		IO::read(l, r);
		update(1, 1, n, l, r, i);
	}
	int q;
	IO::read(q);
	for (int x; q--; ) {
		IO::read(x);
		x = (x + ans - 1) % n + 1;
		update(1, 1, n, x);
		printf("%d\n", ans);
	}
	return 0;
}
posted @ 2020-02-14 09:37  Mrzdtz220  阅读(122)  评论(0编辑  收藏  举报