bzoj4631 踩气球 (树状数组+线段树)

4631: 踩气球

Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 423 Solved: 217
[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 一次操作后询问的答案。答案的顺序应与输入数据的顺序保持一致。

\(L[i]\)为一段全\(0\)区间的左端点,\(R[i]\)为右端点;
把一个点\(i\)变成\(0\),相当于把它左右两段全\(0\)的区间连起来;
此时所有 \(L[i-1]<=l<=i\)\(i<=r<=R[i+1]\) 的区间都会变得愉悦;
然后就变成了二维数点,树状数组+线段树,边界特判一下就行了;
AC GET☆DAZE

#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define N 100039
#define mod 20070831
#define inf 0x3f3f3f3f 
#define ll long long
using namespace std;
struct Seg_Tree
{
	int ls,rs,w;
}tree[N*2*39];
int n,m,q,num[N],L[N],R[N],tot,root[N],ans;
int make_new(int &k)
{
	return !k ? k=++tot : k;
}
void update(int k,int l,int r,int v)
{
	tree[k].w++;
	if(l==r) return;
	int mid=l+r>>1;
	if(v<=mid) update(make_new(tree[k].ls),l,mid,v);
	else update(make_new(tree[k].rs),mid+1,r,v);
}
int query(int k,int l,int r,int lv,int rv)
{
	if(!k || (lv<=l && r<=rv)) return tree[k].w;
	int mid=l+r>>1;
	if(rv<=mid) return query(tree[k].ls,l,mid,lv,rv);
	else if(mid<lv) return query(tree[k].rs,mid+1,r,lv,rv);
	else return query(tree[k].ls,l,mid,lv,mid)+query(tree[k].rs,mid+1,r,mid+1,rv);
}
void update_bit(int p,int v)
{
	while(p<=n)
	{
		update(make_new(root[p]),1,n,v);
		p+=(-p&p);
	}
}
int query_bit(int p,int l,int r)
{
	int res=0;
	while(p)
	{
		res+=query(root[p],1,n,l,r);
		p-=(-p&p);
	}
	return res;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int a=1;a<=n;a++)
	{
		scanf("%d",&num[a]);
		L[a]=R[a]=a;
	}
	for(int a=1,b,c;a<=m;a++)
	{
		scanf("%d%d",&b,&c);
		update_bit(b,c);
	}
	scanf("%d",&q);
	for(int a=1,b,c,d;a<=q;a++)
	{
		scanf("%d",&b);
		((b+=ans-1)%=n)++;
		num[b]--;
		if(!num[b])
		{
			c=((b>1 && !num[b-1]) ? L[b-1] : b);
			d=((b<n && !num[b+1]) ? R[b+1] : b);
			ans+=query_bit(b,b,d)-query_bit(c-1,b,d);
			if(b>1 && !num[b-1] && b<n && !num[b+1])
			{
				L[R[b+1]]=L[b-1],R[L[b-1]]=R[b+1];
			}
			else if(b>1 && !num[b-1]) L[b]=L[b-1],R[L[b-1]]=b;
			else if(b<n && !num[b+1]) L[R[b+1]]=b,R[b]=R[b+1];
		}
		printf("%d\n",ans);
	}
	return 0;
}
posted @ 2018-04-25 12:33  Sinogi  阅读(195)  评论(0编辑  收藏  举报