题面:
有一个长度为n的数组a。现有m组操作。
操作1:将区间[l,r]内的所有数字都整除2。
操作2:输出区间[l,r]内所有数字的和。
Input
第一行输入两个整数n,m(1<=n<=200000,1<=m<=200000)
第二行n个整数,表示数组a (0<=a[i]<=10^9)
接下来m行,每行三个整数op,l,r
——若op=1,表示操作1,将[l,r]内所有数字整除2
——若op=2,表示操作2,输出[l,r]内所有数字的和
Output
对于所有的操作2,输出结果。
Sample Input
5 5
3 4 9 2 7
2 3 4
1 4 5
2 1 5
1 3 4
2 3 5
Sample Output
11
20
7
大致思路:
这个题是不能用lazytag的,因为整除不满足使用lazytag的条件。
比如 对于序列1 3 5 7 9
如果现在要求是 1 1 5
然后求2 1 5
真实答案是 10
如果用lazytag标记的话答案就是12
所以只能进行点修改。
但也有可以优化的地方,如果一个区间的sum已经是0了,那么就没有必要继续递归修改了,因为0/2=0
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=2e5+7; 4 int a[maxn]; 5 long long sum[maxn<<2]; 6 void maintain(int k) 7 { 8 sum[k]=sum[k<<1]+sum[k<<1|1]; 9 } 10 void build(int l,int r,int k) 11 { 12 if(l>r) 13 return ; 14 if(l==r){ 15 sum[k]=a[l]; 16 return ; 17 } 18 int mid=(l+r)>>1; 19 build(l,mid,k<<1); 20 build(mid+1,r,k<<1|1); 21 maintain(k); 22 } 23 void change(int l,int r,int cl,int cr,int k) 24 { 25 if(sum[k]==0) 26 return ; 27 if(l>r||cl>r||cr<l) 28 return ; 29 if(l==r){ 30 sum[k]=sum[k]/2; 31 return ; 32 } 33 34 int mid=(l+r)>>1; 35 change(l,mid,cl,cr,k<<1); 36 change(mid+1,r,cl,cr,k<<1|1); 37 maintain(k); 38 } 39 long long query(int l,int r,int ql,int qr,int k) 40 { 41 if(l>r||ql>r||qr<l) 42 return 0; 43 if(ql<=l&&qr>=r) 44 return sum[k]; 45 if(sum[k]==0) 46 return 0; 47 int mid=(l+r)>>1; 48 long long ans=0; 49 ans=+query(l,mid,ql,qr,k<<1); 50 ans+=query(mid+1,r,ql,qr,k<<1|1); 51 return ans; 52 } 53 int main() 54 { 55 ios::sync_with_stdio(false); 56 memset(sum,0,sizeof(sum)); 57 int n,m,cmd,l,r; 58 cin>>n>>m; 59 for(int i=1;i<=n;++i) 60 cin>>a[i]; 61 build(1,n,1); 62 for(int i=0;i<m;++i){ 63 cin>>cmd>>l>>r; 64 if(cmd==1) 65 change(1,n,l,r,1); 66 else 67 cout<<query(1,n,l,r,1)<<endl; 68 } 69 return 0; 70 }
时间: 2024-10-11 23:08:05