Luogu P3372【模板】线段树 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的结果。
输入输出样例
说明
时空限制:1000ms,128M
数据规模:
对于30%的数据:N<=8,M<=10
对于70%的数据:N<=1000,M<=10000
对于100%的数据:N<=100000,M<=100000
(数据已经过加强^_^,保证在int64/long long数据范围内)
注意long long
1 //2018年2月22日21:12:39 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 using namespace std; 6 7 const int N = 1000000; 8 int n, m; 9 long long a[N]; 10 long long A[N<<2], sum[N<<1], size[N<<1]; 11 12 void change(int k1){ 13 sum[k1] = sum[k1*2] + sum[k1*2+1]; 14 } 15 16 void buildtree(int k1, int l, int r){ 17 size[k1] = r-l+1; 18 if(l == r){ 19 sum[k1] = a[l]; 20 return; 21 } 22 int mid = l+r >> 1; 23 buildtree(k1*2, l, mid); 24 buildtree(k1*2+1, mid+1, r); 25 change(k1); 26 } 27 28 void add(int k1, int x){ 29 A[k1] += x; 30 sum[k1] = sum[k1] + size[k1]*x; 31 } 32 void pushdown(int k1){ 33 if(A[k1]){ 34 add(k1*2, A[k1]); 35 add(k1*2+1, A[k1]); 36 A[k1] = 0; 37 } 38 } 39 40 void addall(int k1, int l, int r, int L, int R, int x){ 41 if(l>R || r<L) return; 42 if(l>=L && r<=R){ 43 add(k1, x); 44 return; 45 } 46 int mid = l+r >> 1; 47 pushdown(k1); 48 addall(k1*2, l, mid, L, R, x); 49 addall(k1*2+1, mid+1, r, L, R, x); 50 change(k1); 51 } 52 53 long long find(int k1, int l, int r, int L, int R){ 54 if(l>R || r<L) return 0; 55 if(l>=L && r<=R) return sum[k1]; 56 int mid = l+r >> 1; 57 pushdown(k1); 58 return (find(k1*2, l, mid, L, R) + find(k1*2+1, mid+1, r, L, R)); 59 } 60 61 int main(){ 62 scanf("%d%d", &n, &m); 63 for(int i=1;i<=n;i++) 64 scanf("%lld", &a[i]); 65 buildtree(1, 1, n); 66 for(int i=1;i<=m;i++){ 67 int k1, k2, k3; 68 scanf("%d%d%d", &k1, &k2, &k3); 69 if(k1 == 1){ 70 long long k4; 71 scanf("%lld", &k4); 72 addall(1, 1, n, k2, k3, k4); 73 }else if(k1 == 2){ 74 printf("%lld\n", find(1, 1, n, k2, k3)); 75 } 76 } 77 78 return 0; 79 }