【北京集训测试赛(七)/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 }