BZOJ 4631 踩气球

Description

Solution

这题的解法非常巧妙啊~
我们发现只有一个箱子中的气球全部被踩完后, 才可能对答案产生贡献, 因此用数组维护每个箱子中剩余的气球个数.
考虑每次可能对处于哪些区间的熊孩子产生影响: 我们设当前箱子为\(p\), 通过链表查找到最小的\(l\)满足\([l, p]\)区间的所有箱子都不含有气球, 以及最大的\(r\)满足\([p, r]\)区间中的所有箱子都不含有气球. 则会变高兴的熊孩子满足其对应区间的左端点在\([l, p]\)中且右端点在\([p, r]\)中. 我们用一颗可持久化线段树来维护每个位置\(p\)有哪些熊孩子满足\(l \le p\), 且将其对应的\(r\)存入线段树中. 每次操作后, 在线段树中容斥即可.

#include <cstdio>
#include <cctype>
#include <algorithm>

namespace Zeonfai
{
	inline int getInt()
	{
		int a = 0, sgn = 1;
		char c;
		while(! isdigit(c = getchar())) if(c == '-') sgn *= -1;
		while(isdigit(c)) a = a * 10 + c - '0', c = getchar();
		return a * sgn;
	}
}
const int N = (int)1e5, M = (int)1e5;
int n, m;
struct bearChild
{
	int L, R;
	inline int friend operator <(bearChild a, bearChild b)
	{
		return a.L == b.L ? a.R < b.R : a.L < b.L;
	}
}chd[M];
struct segmentTrees
{
	struct node
	{
		node *suc[2];
		int cnt;
		inline node() {cnt = 0; suc[0] = suc[1] = NULL;}
	};
	node *rt[N + 1];
	node* build(int L, int R)
	{
		node *u = new node;
		if(L == R) return u;
		u->suc[0] = build(L, L + R >> 1); u->suc[1] = build((L + R >> 1) + 1, R);
		return u;
	}
	inline void build() {rt[0] = build(1, n);}
	inline void newTree(int id) {rt[id] = rt[id - 1];}
	inline node* insert(node *_u, node *u, int L, int R, int pos)
	{
		if(u == _u) u = new node, *u = *_u;
		++ u->cnt;
		if(L == R) return u;
		if(pos <= L + R >> 1) u->suc[0] = insert(_u->suc[0], u->suc[0], L, L + R >> 1, pos);
		else u->suc[1] = insert(_u->suc[1], u->suc[1], (L + R >> 1) + 1, R, pos);
		return u; 
	}
	inline void insert(int id, int pos)
	{
		rt[id] = insert(rt[id - 1], rt[id], 1, n, pos);
	}
	int query(node *u, int curL, int curR, int L, int R)
	{
		if(curL >= L && curR <= R) return u->cnt;
		int mid = curL + curR >> 1;
		int res = 0;
		if(L <= mid) res += query(u->suc[0], curL, mid, L, R);
		if(R > mid) res += query(u->suc[1], mid + 1, curR, L, R);
		return res;
	}
	inline int query(int id, int L, int R)
	{
		return query(rt[id], 1, n, L, R);
	}
}seg;
int main()
{
	
	#ifndef ONLINE_JUDGE
	
	freopen("balloon.in", "r", stdin);
	freopen("balloon.out", "w", stdout);
	
	#endif
	
	using namespace Zeonfai;
	n = getInt(), m = getInt();
	static int a[N + 1];
	for(int i = 1; i <= n; ++ i) a[i] = getInt();
	for(int i = 0; i < m; ++ i) chd[i].L = getInt(), chd[i].R = getInt();
	std::sort(chd, chd + m);
	seg.build();
	for(int i = 1, p = 0; i <= n; ++ i)
	{
		seg.newTree(i);
		for(; p < m && chd[p].L == i; ++ p) seg.insert(i, chd[p].R);
	}
	static int pre[N + 1], nxt[N + 1];
	for(int i = 1; i <= n; ++ i) pre[i] = i - 1, nxt[i] = i + 1;
	pre[1] = nxt[n] = -1;
	int q = getInt(), ans = 0;
	for(int i = 0; i < q; ++ i)
	{
		int pos = (getInt() + ans - 1) % n + 1; -- a[pos];
		if(! a[pos])
		{
			ans += seg.query(pos, pos, ~ nxt[pos] ? nxt[pos] - 1 : n);
			if(~ pre[pos]) ans -= seg.query(pre[pos], pos, ~ nxt[pos] ? nxt[pos] - 1 : n);
			if(~ nxt[pos]) pre[nxt[pos]] = pre[pos];
			if(~ pre[pos]) nxt[pre[pos]] = nxt[pos];
		}
		printf("%d\n", ans);
	}
}
posted @ 2017-08-11 21:58  Zeonfai  阅读(127)  评论(0编辑  收藏  举报