题意
在一个数据结构上实现区间加一,询问区间内$a_i/b_i$的和,$b_i$是事先给出的一个序列
思路
线段树维护区间最小值与区间和,区间最小值维护$a_i$序列,每次加操作区间最小值减一,如果最小值减到零,就去暴力更新区间和,区间和维护的是答案的和。
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e5+7; 4 struct node{ 5 int b,low,sum; 6 }sgt[maxn*4]; 7 int lazy[maxn*4]; 8 void pushup(int rt) 9 { 10 sgt[rt].low=min(sgt[rt*2].low,sgt[rt*2+1].low); 11 sgt[rt].sum=sgt[rt*2].sum+sgt[rt*2+1].sum; 12 } 13 void pushdown(int L,int R,int rt) 14 { 15 if(lazy[rt]) 16 { 17 sgt[rt*2].low-=lazy[rt]; 18 sgt[rt*2+1].low-=lazy[rt]; 19 lazy[rt*2]+=lazy[rt]; 20 lazy[rt*2+1]+=lazy[rt]; 21 lazy[rt]=0; 22 } 23 if(sgt[rt].low<=0) 24 { 25 if(L==R) 26 { 27 while(sgt[rt].low<=0) 28 { 29 sgt[rt].low+=sgt[rt].b; 30 sgt[rt].sum++; 31 } 32 return; 33 } 34 int mid=L+R>>1; 35 pushdown(L,mid,rt*2); 36 pushdown(mid+1,R,rt*2+1); 37 pushup(rt); 38 } 39 } 40 void build(int l,int r,int rt) 41 { 42 if(l==r) 43 { 44 scanf("%d",&sgt[rt].b); 45 sgt[rt].low=sgt[rt].b; 46 return; 47 } 48 int mid=l+r>>1; 49 build(l,mid,rt*2); 50 build(mid+1,r,rt*2+1); 51 pushup(rt); 52 } 53 void update(int l,int r,int L,int R,int rt) 54 { 55 pushdown(L,R,rt); 56 if(L>=l&&R<=r) 57 { 58 sgt[rt].low-=1; 59 lazy[rt]+=1; 60 return ; 61 } 62 int mid=L+R>>1; 63 if(mid>=l) 64 update(l,r,L,mid,rt*2); 65 if(mid<r) 66 update(l,r,mid+1,R,rt*2+1); 67 pushup(rt); 68 } 69 int query(int l,int r,int L,int R,int rt) 70 { 71 pushdown(L,R,rt); 72 if(L>=l&&R<=r) 73 { 74 return sgt[rt].sum; 75 } 76 int mid=L+R>>1; 77 int ret=0; 78 if(mid>=l) 79 ret+=query(l,r,L,mid,rt*2); 80 if(mid<r) 81 ret+=query(l,r,mid+1,R,rt*2+1); 82 return ret; 83 } 84 int main() 85 { 86 int n,q; 87 while(~scanf("%d%d",&n,&q)) 88 { 89 memset(sgt,0,sizeof(sgt)); 90 memset(lazy,0,sizeof(lazy)); 91 build(1,n,1); 92 char op[10]; 93 while(q--) 94 { 95 int l,r; 96 scanf("%s",op); 97 scanf("%d%d",&l,&r); 98 if(op[0]=='a') 99 update(l,r,1,n,1); 100 else{ 101 int ans=query(l,r,1,n,1); 102 printf("%d ",ans); 103 } 104 } 105 } 106 }
后记
还是要学会线段树的灵活运用的!感觉提升了一点对线段树的认识。