【北京集训测试赛(七)/BZOJ4631】踩气球(Balloon)-线段树-STL-Vector

Problem 踩气球

题目大意

给m个区间和一个数列,每次对其中一个数减一,强制在线求每次操作后区间内数字全都为0的区间。

Solution

对于数列开一个线段树。对于线段树每一个点开一个vector存区间的id。

这样我们一共最多会存下$\log m$个id。

对于每次操作,维护线段树sum值。

当我们将一个数减到了零,那么对于到根路径上的每一个点扫一遍。

如果这个点的sum值变成零了那么就扫一遍这个点的vector

判断这个id的区间是否被减完了(额外开一个数组维护就行了)

如果减成零了那么就ans++。最后我们清空这个vector。

这样下来,因为每个vector中的东西最多只会访问一遍(然后就删了),

所以复杂度是$O(q \log n+\log m)$

AC Code

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <vector>
 5 using namespace std;
 6 struct Node{
 7     int l,r,sum;
 8     vector<int> v;
 9 }a[500010];
10 int lastans=0,bal[100010],ans=0,x,f[100010];
11 int q,l,r,m,n;
12 void sg_update(int now){
13     if(a[now].sum)return;
14     for(vector<int>::iterator it=a[now].v.begin();it!=a[now].v.end();it++){
15         bal[*it]-=a[now].r-a[now].l+1;
16         if(!bal[*it])ans++;
17     }
18     a[now].v.clear();
19 }
20 void sg_build(int l,int r,int now){
21     a[now].l=l;a[now].r=r;
22     if(l==r){
23         a[now].sum=f[l];
24         return;
25     }
26     int mid=(l+r)>>1;
27     sg_build(l,mid,now<<1);
28     sg_build(mid+1,r,now<<1|1);
29     a[now].sum=a[now<<1].sum+a[now<<1|1].sum;
30     return;
31 }
32 int sg_delete(int now,int x){
33     if(a[now].l==a[now].r){
34         a[now].sum--;
35         sg_update(now);
36         return ans;
37     }
38     int mid=(a[now].l+a[now].r)>>1;
39     if(x<=mid)sg_delete(now<<1,x);
40     else sg_delete(now<<1|1,x);
41     a[now].sum--;
42     sg_update(now);
43     return ans;
44 }
45 void sg_add(int l,int r,int now,int x){
46     if(l<=a[now].l&&r>=a[now].r){
47         a[now].v.push_back(x);
48         bal[x]=r-l+1;
49         return;
50     }
51     int mid=(a[now].l+a[now].r)>>1;
52     if(l<=mid)sg_add(l,r,now<<1,x);
53     if(mid<r)sg_add(l,r,now<<1|1,x);
54 
55 }
56 int main(){
57 //  freopen("c.in","r",stdin);
58     scanf("%d%d",&n,&m);
59     for(int i=1;i<=n;i++)
60         scanf("%d",&f[i]);
61     sg_build(1,n,1);
62     for(int i=1;i<=m;i++)
63         scanf("%d%d",&l,&r),
64         sg_add(l,r,1,i);
65     scanf("%d",&q);
66     for(int i=1;i<=q;i++)
67         scanf("%d",&x),
68         lastans=sg_delete(1,(x+lastans-1)%n+1),
69         printf("%d\n",ans);
70     return 0;
71 }

 

转载于:https://www.cnblogs.com/skylynf/p/7346504.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值