1 #include <iostream>
2 #include<stdio.h>
3 # define LC (p<<1) //该节点的左孩子
4 # define RC (p<<1|1)//右孩子
5 using namespace std;
6
7 //很类似与树状数组
8 int n,m;
9 struct Segment_Tree
10 {
11 int sum;
12 int lazy;//懒标记
13 }tree[1000000]; //线段树数组
14 int a[1000000];
15 void build_tree(int p,int l,int r) //p当前节点,l,r,表示范围
16 {
17 if(l==r) //递归的出口
18 {
19 tree[p].sum=a[l]; //就是赋予叶子节点的值
20 }
21 else
22 {
23 int mid=(r+l)/2;//左右分开建树
24 build_tree(LC,l,mid);
25 build_tree(RC,mid+1,r);
26 tree[p].sum=tree[LC].sum+tree[RC].sum;//左右孩子节点的值相加就是父节点的值
27 }
28
29 }
30 void free(int p,int l,int r,int k)
31 {
32 tree[p].lazy+=k;
33 tree[p].sum+=k*(r-l+1);//将当前节点假装覆盖想要的值,这个值是你想在这个区间进行修改的值的和
34 return;
35 }
36 void pushdown(int p,int l,int r)
37 {
38 int mid=(r+l)/2;
39 free(LC,l,mid,tree[p].lazy);
40 free(RC,mid+1,r,tree[p].lazy);
41 tree[p].lazy=0;//两个孩子有了假想覆盖值之后需要消去父节点的覆盖值
42 return;
43 }
44 void update(int L,int R,int p,int l,int r,int k)
45 {
46
47 int mid=(r+l)/2;
48 if(l>=L&&r<=R) //维护区间刚好在修改区间的里面,就优先把维护区间覆盖
49 {
50 free(p,l,r,k);
51 return ;
52 }
53 else
54 {
55 if(L<=mid)
56 {
57 update(L,R,LC,l,mid,k);
58 }
59 if(R>mid)
60 {
61 update(L,R,RC,mid+1,r,k);
62 }
63
64 }
65 tree[p].sum=tree[LC].sum+tree[RC].sum;//节点值的修改使得这个sum需要一直修改
66 return ;
67 }
68 int query(int L,int R,int p,int l,int r) //区间查询
69 {
70 int res=0;
71 if(l>=L&&r<=R)
72 {
73 return tree[p].sum;
74 }
75
76
77 pushdown(p,l,r);
78
79 int mid=(r+l)/2;
80 if(L<=mid)
81 {
82 res+=query(L,R,LC,l,mid);
83 }
84 if(R>mid)
85 {
86 res+=query(L,R,RC,mid+1,r);
87 }
88 return res;
89 }
90 int main()
91 {
92 int x,y,c,k;
93 scanf("%d%d",&n,&m);
94 register int i;
95 for(i=1;i<=n;i++){
96 scanf("%d",&a[i]);
97 }
98 build_tree(1,1,n);
99 for(i=1;i<=m;i++){
100 scanf("%d",&c);
101 if(c==1){
102 scanf("%d%d%d",&x,&y,&k);
103 update(x,y,1,1,n,k);
104 }else{
105 scanf("%d%d",&x,&y);
106 printf("%d\n",query(x,y,1,1,n));
107 }
108 }
109 return 0;
110 }