zoukankan      html  css  js  c++  java
  • 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
    ", ans);
    	}
    }
    
  • 相关阅读:
    java通过dom读写xml文件
    SWT
    Eclipse RCP学习资料
    Integration Guide
    一个Linux命令,黑客帝国
    GET和POST两种基本请求方法的区别
    贫血模式-AnemicDomainModel
    Synchronized锁在Spring事务管理下,为啥还线程不安全?
    redis 集群配置、启动
    redis cluster集群
  • 原文地址:https://www.cnblogs.com/ZeonfaiHo/p/7348178.html
Copyright © 2011-2022 走看看