zoukankan      html  css  js  c++  java
  • 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
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    UILabel 设置字体间的距离 和 行与行间的距离
    IB_DESIGNABLE 和 IBInspectable 的使用
    干货博客
    GitHub克隆速度太慢解决方案
    实时(RTC)时钟,系统时钟和CPU时钟
    折腾了好久的vscode配置c/c++语言环境(Windows环境下)
    c语言中的malloc函数
    记录一下关于在工具类中更新UI使用RunOnUiThread犯的极其愚蠢的错误
    记录关于Android多线程的一个坑
    Android中限制输入框最大输入长度
  • 原文地址:https://www.cnblogs.com/Sinogi/p/8942006.html
Copyright © 2011-2022 走看看