【BZOJ 4631】4631: 踩气球 (线段树)

4631: 踩气球

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 316  Solved: 153

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

 

 

【分析】

   我觉得这个跟扫描线的线段树维护是有异曲同工之妙的。

   把线段树上覆盖熊孩子区间的点标记。当这个点全部被清0的时候让cnt--,当熊孩子的log个区间减剩0,ans++。

  看代码易懂。

  【可以思考一下操作变成区间的时候怎么办

 

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 using namespace std;
  7 #define Maxn 2000010
  8 #define INF 0xfffffff
  9 #define LL long long
 10 
 11 int a[Maxn];
 12 
 13 struct node
 14 {
 15     int l,r,lc,rc;
 16 }tr[Maxn*2];
 17 
 18 int tot;
 19 LL sm[Maxn],ss[Maxn];
 20 int build(int l,int r)
 21 {
 22     int x=++tot;
 23     tr[x].l=l;tr[x].r=r;
 24     ss[x]=sm[r]-sm[l-1];
 25     if(l<r)
 26     {
 27         int mid=(l+r)>>1;
 28         tr[x].lc=build(l,mid);
 29         tr[x].rc=build(mid+1,r);
 30     }
 31     else tr[x].lc=tr[x].rc=0;
 32     return x;
 33 }
 34 
 35 int first[Maxn],nt[Maxn],cnt[Maxn],tto[Maxn];
 36 int len;
 37 void add(int x,int id)
 38 {
 39     tto[++len]=id;nt[len]=first[x];first[x]=len;cnt[id]++;
 40 }
 41 
 42 void ins(int x,int l,int r,int id)
 43 {
 44     if(tr[x].l==l&&tr[x].r==r)
 45     {
 46         add(x,id);return;
 47     }
 48     int mid=(tr[x].l+tr[x].r)>>1;
 49     if(r<=mid) ins(tr[x].lc,l,r,id);
 50     else if(l>mid) ins(tr[x].rc,l,r,id);
 51     else {ins(tr[x].lc,l,mid,id);ins(tr[x].rc,mid+1,r,id);}
 52 }
 53 
 54 int ans;
 55 void solve(int x)
 56 {
 57     for(int i=first[x];i;i=nt[i])
 58     {
 59         int y=tto[i];
 60         cnt[y]--;
 61         if(cnt[y]==0) ans++;
 62     }
 63 }
 64 
 65 void change(int x,int y)
 66 {
 67     ss[x]--;
 68     if(ss[x]==0) solve(x);
 69     if(tr[x].l==tr[x].r) return;
 70     int mid=(tr[x].l+tr[x].r)>>1;
 71     if(y<=mid) change(tr[x].lc,y);
 72     else change(tr[x].rc,y);
 73 }
 74 
 75 int main()
 76 {
 77     int n,m;
 78     scanf("%d%d",&n,&m);
 79     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
 80     sm[0]=0;
 81     for(int i=1;i<=n;i++) sm[i]=sm[i-1]+a[i];
 82     build(1,n);
 83     memset(first,0,sizeof(first));
 84     for(int i=1;i<=m;i++)
 85     {
 86         int l,r;
 87         scanf("%d%d",&l,&r);
 88         ins(1,l,r,i);
 89     }
 90     int q;
 91     scanf("%d",&q);
 92     for(int i=1;i<=q;i++)
 93     {
 94         int x;scanf("%d",&x);
 95         x=(x+ans-1)%n+1;
 96         change(1,x);
 97         printf("%d\n",ans);
 98     }
 99     return 0;
100 }
View Code

 

2017-04-10 14:37:10

posted @ 2017-04-10 14:37  konjak魔芋  阅读(308)  评论(0编辑  收藏  举报