BZOJ 4631: 踩气球

4631: 踩气球

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 275  Solved: 140
[Submit][Status][Discuss]

Description

六一儿童节到了, SHUXK 被迫陪着M个熊孩子玩一个无聊的游戏:有N个盒子从左到右排成一排,第i个盒子里装着Ai个气球。

SHUXK 要进行Q次操作,每次从某一个盒子里拿出一个没被踩爆的气球,然后熊孩子们就会立刻把它踩爆。

这M个熊孩子每个人都指定了一个盒子区间[Li, Ri]。 如果某一个时刻,一个熊孩子发现自己选定的盒子区间[Li, Ri]中的所

有气球都已经被踩爆了,他就会非常高兴(显然之后他一直会很高兴)。

为了不辜负将自己的任务强行塞给 SHUXK 的那个人的期望, SHUXK 想向你询问:

他每次操作过后会有多少个熊孩子很高兴。

Input

第一行包含两个正整数N和M,分别表示盒子和熊孩子的个数。

第二行包含N个正整数Ai( 1 < = Ai < = 10^5),表示每个盒子里气球的数量。

以下M行每行包含两个正整数Li, Ri( 1 < = Li < = Ri < = N),分别表示每一个熊孩子指定的区间。

以下一行包含一个正整数Q,表示 SHUXK 操作的次数。

以下Q行每行包含一个正整数X,表示这次操作是从第X个盒子里拿气球。为

了体现在线,我们对输入的X进行了加密。

假设输入的正整数是x‘,那么真正的X = (x‘ + Lastans − 1)Mod N + 1。其

中Lastans为上一次询问的答案。对于第一个询问, Lastans = 0。

输入数据保证1 < = x‘ < = 10^9, 且第X个盒子中有尚未被踩爆的气球。

N < = 10^5 ,M < = 10^5 ?,Q < = 10^5

Output

包含Q行,每行输出一个整数,表示 SHUXK 一次操作后询问的

答案。答案的顺序应与输入数据的顺序保持一致。

Sample Input

5 3
1 1 1 1 1
5 5
2 2
1 3
5
4
2
5
2
3

Sample Output

0
1
1
2
3
【样例说明】
实际上每次操作的盒子是: 4 2 1 3 5
在第二次操作后,第二个熊孩子会高兴 (区间[2,2]中的气球已经全部被踩爆)。
在第四次操作后,第三个熊孩子会高兴(区间[1,3]中的气球已经全部被踩爆)。
在第五次操作后,第一个熊孩子会高兴(区间[5,5]中的气球已经全部被踩爆)。

HINT

Source

分析:

我一开始看成离线的了...然后这不是水水嘛,就开始写,发现是在线QwQ~~~

既然我们必须每一次去查询当前区间全部为0的区间个数有多少个,我们不妨计算每次新增了多少个区间,考虑每一次把一个盒子变为空,就会合并前后两个全0区间,那么当前的点对新增答案的贡献就是左端点位于[包含当前点的极大0区间左端点,当前点]并且右端点位于[当前点,包含当前点的极大子区间的右端点]的区间个数,那么我们维护一个可持久化线段树,每个可持久化线段树中维护右端点位于某个点的区间个数,然后每一次二分合法左端点区间的可持久化线段树,然后查询合法右端点区间个数,更新答案就好了...

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std;

const int maxn=100000+5,maxm=7000000+5;

int n,m,Q,ans,tot,a[maxn],ls[maxm],rs[maxm],sum[maxm],root[maxn],fapre[maxn],fanxt[maxn];

struct M{

	int l,r;

	friend bool operator < (M a,M b){
		if(a.l!=b.l)
			return a.l<b.l;
		return a.r<b.r;
	}

}q[maxn];

inline int findpre(int x){
	return fapre[x]==x?x:fapre[x]=findpre(fapre[x]);
}

inline int findnxt(int x){
	return fanxt[x]==x?x:fanxt[x]=findnxt(fanxt[x]);
}

inline void change(int l,int r,int pos,int x,int &y){
	y=++tot;sum[y]=sum[x]+1;
	if(l==r)
		return;
	int mid=(l+r)>>1;ls[y]=ls[x];rs[y]=rs[x];
	if(pos<=mid)
		change(l,mid,pos,ls[x],ls[y]);
	else
		change(mid+1,r,pos,rs[x],rs[y]);
}

inline int query(int l,int r,int L,int R,int x,int y){
	if(l==L&&r==R)
		return sum[y]-sum[x];
	int mid=(l+r)>>1;
	if(R<=mid)
		return query(l,mid,L,R,ls[x],ls[y]);
	else if(L>mid)
		return query(mid+1,r,L,R,rs[x],rs[y]);
	else
		return query(l,mid,L,mid,ls[x],ls[y])+query(mid+1,r,mid+1,R,rs[x],rs[y]);
}

inline int findgreater(int x){
	int l=1,r=m,res=n+1;
	while(l<=r){
		int mid=(l+r)>>1;
		if(q[mid].l>=x)
			res=mid,r=mid-1;
		else
			l=mid+1;
	}
	return res;
}

inline int findlower(int x){
	int l=1,r=m,res=0;
	while(l<=r){
		int mid=(l+r)>>1;
		if(q[mid].l<=x)
			res=mid,l=mid+1;
		else
			r=mid-1;
	}
	return res;
}

signed main(void){
	scanf("%d%d",&n,&m);fanxt[n+1]=n+1;
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]),fapre[i]=i,fanxt[i]=i;
	for(int i=1;i<=m;i++)
		scanf("%d%d",&q[i].l,&q[i].r);
	sort(q+1,q+m+1);scanf("%d",&Q);ans=0;
	for(int i=1;i<=m;i++)
		change(1,n,q[i].r,root[i-1],root[i]);
	for(int i=1,pos,x,y,l,r;i<=Q;i++){
		scanf("%d",&pos);pos=(pos+ans-1)%n+1;
		a[pos]--;
		if(a[pos]!=0) {printf("%d\n",ans);continue;}
		x=findpre(pos-1)+1;
		y=findnxt(pos+1)-1;
		fapre[pos]=pos-1;
		fanxt[pos]=pos+1;
		l=findgreater(x);
		r=findlower(pos);
		if(l<=r)
			ans+=query(1,n,pos,y,root[l-1],root[r]);
		printf("%d\n",ans);
	}
	return 0;
}

  



By NeighThorn

时间: 2024-08-06 11:50:37

BZOJ 4631: 踩气球的相关文章

bzoj 4631: 踩气球 线段树合并

4631: 踩气球 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 265  Solved: 136[Submit][Status][Discuss] Description 六一儿童节到了, SHUXK 被迫陪着M个熊孩子玩一个无聊的游戏:有N个盒子从左到右排成一排,第i个盒子里装着Ai个气球. SHUXK 要进行Q次操作,每次从某一个盒子里拿出一个没被踩爆的气球,然后熊孩子们就会立刻把它踩爆. 这M个熊孩子每个人都指定了一个盒子区间[Li, R

【BZOJ-4631】踩气球 线段树 + STL

4631: 踩气球 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 224  Solved: 114[Submit][Status][Discuss] Description 六一儿童节到了, SHUXK 被迫陪着M个熊孩子玩一个无聊的游戏:有N个盒子从左到右排成一排,第i个盒子里装着Ai个气球. SHUXK 要进行Q次操作,每次从某一个盒子里拿出一个没被踩爆的气球,然后熊孩子们就会立刻把它踩爆. 这M个熊孩子每个人都指定了一个盒子区间[Li, R

bzoj4631踩气球

bzoj4631踩气球 题意: 有一个序列和一个区间集合,每次将序列中的一个数-1,求此时集合里有多少个区间和为0.序列大小≤100000,区间数≤100000,操作数≤100000. 题解: 此题解法其实并不难,对序列建线段树,用线段树每个节点维护区间和及覆盖该区间的集合内的区间的链表,同时记录每个集合内区间被分割为多少个区间.操作时就把查询经过的节点的区间和-1,如果为0则将覆盖该节点的区间的分割数-1,当分割数为0就让答案++.问题是复杂度,总是要遍历链表不会很慢吗?后来仔细想了一下,每次

noj算法 踩气球 回溯法

描述: 六一儿童节,小朋友们做踩气球游戏,气球的编号是1-100,两位小朋友各踩了一些气球,要求他们报出自己所踩气球的编号的乘积.现在需要你编一个程序来判断他们的胜负,判断的规则是这样的:如果两人都说了真话,数字大的人赢:如果两人都说了假话,数字大的人赢:如果报小数字的人说的是真话而报大数字的人说谎,则报小数字的人赢(注意:只要所报的小数字是有可能的,即认为此人说了真话). 输入: 输入为两个数字,0 0表示结束: 输出: 输出为获胜的数字. 输入样例: 36 62 49 343 0 0 输出样

P4215 踩气球

题目描述 六一儿童节到了,SHUXK被迫陪着\(M\)个熊孩子玩一个无聊的游戏:有\(N\)个盒子从左到右排成一排,第\(i\)个盒子里装着\(A_i\)?个气球.SHUXK要进行\(Q\)次操作,每次从某一个盒子里拿出一个没被踩爆的气球,然后熊孩子们就会立刻把它踩爆. 这\(M\)个熊孩子每个人都指定了一个盒子区间\([L_i?,R_i?]\).如果某一个时刻,一个熊孩子发现自己选定的盒子区间\([L_i?,R_i?]\)中的所有气球都已经被踩爆了,他就会非常高兴(显然之后他一直会很高兴).

bzoj4631 踩气球

题意:给定一个长为n的正整数序列,并给定m个区间,q次操作,每次操作将一个位置的数值减1,并在操作后输出给定的m个区间中有多少个区间的区间和为0.强制在线. 数据范围:n,m,q<=10^5 首先只有某个位置x的气球数目从1变成0的时候才会对答案产生影响,那么我们考虑这时什么样的区间的区间和会变成0.这样的区间之前一定包含位置x而且只有位置x不为0,也就是由位置x再加上x左边一段0和x右边一段0组成(这两段0可能不存在).我们找出x左边尽量长的一段连续的0和x右边尽量长的一段连续的0(这两段连续

【bzoj4631】踩气球 线段树

题解: 真是很zz 我都想到线段树分治的思路了... 不过还是一道好题 首先跟线段树分治一样将区间投射到线段树上去 每次修改如果该个区间修改为0,则对他们对应的特定区间-1 这样每个区间会有一次变0,每个特定区间对应log个 复杂度nlogn 代码: 原文地址:https://www.cnblogs.com/yinwuxiao/p/9404708.html

记录 [补档]

数学 概率论 计数问题 数论 线性代数 博弈论 比赛经验 不要通过数据大小猜测正解的时间复杂度. 把一个方法想到底. DP题假如实在不会的话, 果断跳过, 找思维量更小的数据结构题. 一些方法 二分 DP, 尤其多想矩阵乘法优化DP 网络流 FFT 日程表 Fri, Nov 10 明天就是NOIp了. 从上次记录到现在已经将近一个月了, 这个月, 真心没有进步多少, 完全不再状态. 希望不要AFO吧. 这可能是最后一篇记录了. Sun, Oct 22 AHOI 2009 中国象棋: 统计在棋盘上

项目管理学习笔记之二.工作分解

项目管理个人能力-- 计划分解的能力在项目管理里面,计划分解是一种非常重要的能力和技术方法.它的英文缩写叫做WBS, work breakdown structures,它是教会我们怎么样把一个复杂的问题简单化.工作分解大体可以分成两种分解方式,分别是按时间分解和按可交付成果分解. 1.1. 按时间分解 所有的项目都会有确定的开始和结束时间,所以,从理论上,每个项目都可以按时间来分解.根据时间节点来划分项目阶段来进行管理的好处是不会有遗漏的工作.只要这个项目的时间节点是清晰的,按时间来分解的话,