线段树练习
时间限制: 3 s
空间限制: 128000 KB
题目等级 : 大师 Master
题目描述
给你N个数,有两种操作:
1:给区间[a,b]的所有数增加X
2:询问区间[a,b]的数的和。
输入描述
第一行一个正整数n,接下来n行n个整数,
再接下来一个正整数Q,每行表示操作的个数,
如果第一个数是1,后接3个正整数,
表示在区间[a,b]内每个数增加X,如果是2,
表示操作2询问区间[a,b]的和是多少。
输出描述
对于每个询问输出一行一个答案
样例输入
3
1
2
3
2
1 2 3 2
2 2 3
样例输出
9
数据范围及提示
1<=n<=200000
1<=q<=200000
#include<cstdio> int m,n,x,y; long long a[200005]; long long ans,z; struct ty{ int l,r; long long data,sum; } t[1000005]; long long buid(int x,int y,int k) { t[k].l=x;t[k].r=y; if(x!=y){ int q,p; q=buid(x,(x+y)/2,2*k); p=buid((x+y)/2+1,y,2*k+1); t[k].sum=q+p; return t[k].sum; } else return t[k].sum=a[x]; } void updata(int k) { t[k*2].data+=t[k].data; t[k*2+1].data+=t[k].data; t[k*2].sum+=t[k].data*(t[k*2].r-t[k*2].l+1); t[k*2+1].sum+=t[k].data*(t[k*2+1].r-t[k*2+1].l+1); t[k].data=0; } int jia(int k,int x,int y,int z) { if(t[k].l>=x&&t[k].r<=y){ t[k].data+=z; t[k].sum+=z*(t[k].r-t[k].l+1); } else{ if(t[k].data!=0) updata(k); if(x<=(t[k].l+t[k].r)/2) jia(k*2,x,y,z); if(y>(t[k].l+t[k].r)/2) jia(k*2+1,x,y,z); t[k].sum=t[k*2].sum+t[k*2+1].sum; } } long long find(int k,int x,int y) { if(x<=t[k].l&&y>=t[k].r) return t[k].sum; else{ if(t[k].data!=0) updata(k); long long zh=0; if(x<=(t[k].l+t[k].r)/2) zh+=find(k*2,x,y); if(y>(t[k].l+t[k].r)/2) zh+=find(k*2+1,x,y); return zh; } } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); buid(1,n,1); scanf("%d",&m); int g; for(int i=1;i<=m;i++) { scanf("%d",&g); if(g==1) { scanf("%d%d%d",&x,&y,&z); jia(1,x,y,z); } else { scanf("%d%d",&x,&y); ans=find(1,x,y); printf("%lld ",ans); } } return 0; }