线段树 1
题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。 接下来M行每行包含3或4个整数,表示一个操作,具体如下: 操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k 操作2: 格式:2 x y 含义:输出区间[x,y]内每个数的和 输出格式: 输出包含若干行整数,即为所有操作2的结果。 输入输出样例 输入样例#1: 5 5 1 5 4 2 3 2 2 4 1 2 3 2 2 3 4 1 1 5 1 2 1 4 输出样例#1: 11 8 20 说明 时空限制:1000ms,128M 数据规模: 对于30%的数据:N<=8,M<=10 对于70%的数据:N<=1000,M<=10000 对于100%的数据:N<=100000,M<=100000 (数据已经过加强^_^,保证在int64/long long数据范围内)
1 #include<iostream> 2 #include<cstdio> 3 #define ll long long 4 using namespace std; 5 const ll N=100002; 6 ll n,a[N],m,add[N*10],sum[N*10]; 7 void build(ll o,ll l,ll r) 8 { 9 if(l==r) 10 { 11 sum[o]=a[l]; 12 return; 13 } 14 ll mid=(l+r)>>1; 15 build(o<<1,l,mid); 16 build(o<<1|1,mid+1,r); 17 sum[o]=sum[o<<1]+sum[o<<1|1]; 18 } 19 ll op,x,y,k; 20 void down(ll o,ll l,ll r,ll mid) 21 { 22 if(add[o]) 23 { 24 add[o<<1]+=add[o]; 25 sum[o<<1]+=add[o]*(mid-l+1); 26 27 add[o<<1|1]+=add[o]; 28 sum[o<<1|1]+=add[o]*(r-(mid+1)+1); 29 30 add[o]=0; 31 } 32 } 33 void up(ll o,ll l,ll r,ll x,ll y,ll k) 34 { 35 if(x<=l && y>=r) 36 { 37 add[o]+=k; 38 sum[o]+=k*(r-l+1); 39 return; 40 } 41 ll mid=(l+r)>>1; 42 down(o,l,r,mid); 43 if(x<=mid)up(o<<1,l,mid,x,y,k); 44 if(y>=mid+1)up(o<<1|1,mid+1,r,x,y,k); 45 sum[o]=sum[o<<1]+sum[o<<1|1]; 46 } 47 ll query(ll o,ll l,ll r,ll x,ll y) 48 { 49 if(x<=l && y>=r) 50 { 51 down(o,l,r,(l+r)>>1); 52 return sum[o]; 53 } 54 ll mid=(l+r)>>1; 55 down(o,l,r,mid); 56 ll tot=0; 57 if(x<=mid)tot+=query(o<<1,l,mid,x,y); 58 if(y>mid)tot+=query(o<<1|1,mid+1,r,x,y); 59 return tot; 60 } 61 int main() 62 { 63 scanf("%lld%lld",&n,&m); 64 for(ll i=1;i<=n;i++) scanf("%d",&a[i]); 65 build(1,1,n); 66 while(m--) 67 { 68 scanf("%lld%lld%lld",&op,&x,&y); 69 if(op==1) 70 { 71 scanf("%lld",&k); 72 up(1,1,n,x,y,k); 73 }else{ 74 printf("%lld\n",query(1,1,n,x,y)); 75 } 76 } 77 return 0; 78 }