线段树1求调……
#include <bits/stdc++.h>
#define int long long
using namespace std;
int f[400010],a[400010],tag[400010];
void maketag(int u,int len,int x) { //节点 区间长度 值
tag[u] += x;
f[u] += len * x;
}
void pushdown(int u,int l,int r) { //树里的点 管辖区间左右端点
int mid = (l + r) >> 1;
maketag(u + u,mid - l + 1,tag[u]); //懒标记下放
maketag(u + u + 1,r - mid,tag[u]);
tag[u] = 0;
}
void buildtree(int u,int l,int r) { //建树
if (l == r) {
f[u] = a[l];
return ;
}
int mid = (l + r) >> 1;
buildtree(u + u,l,mid);
buildtree(u + u + 1,mid + 1,r);
f[u] = f[u + u] + f[u + u + 1];
}
bool inrange(int l,int r,int ll,int rr) {
//判断[l,r]是否被[ll,rr]包含
return (l <= ll) && (r >= rr);
}
bool outofrange(int l,int r,int ll,int rr) {
//判断[l,r]是否和[ll,rr]完全不相交
return (r < ll) || (l > rr);
}
int query(int u,int l1,int r1,int l2,int r2) { //当前节点 管辖区间左端点 右端点 查询左端点 右端点
if (inrange(l1,r1,l2,r2)) return f[u]; //如果被包含直接返回区间和
else if (!outofrange(l1,r1,l2,r2)) {
int mid = (l1 + r1) >> 1;
pushdown(u,l1,r1); //先下放懒标记
return query(u + u,l1,mid,l2,r2) + query(u + u + 1,mid + 1,r1,l2,r2);
} else return 0; //完全不相交
}
void update(int u,int l1,int r1,int l2,int r2,int val) { //当前节点 管辖区间左端点 右端点 修改左端点 右端点 值
if (inrange(l1,r1,l2,r2)) maketag(u,r1 - l1 + 1,val); //完全包含就直接打标记
else if (!outofrange(l1,r1,l2,r2)) {
int mid = (l1 + r1) >> 1;
pushdown(u,r1,r2); //懒标记下放
update(u + u,l1,mid,l2,r2,val);
update(u + u + 1,mid + 1,r1,l2,r2,val);
f[u] = f[u + u] + f[u + u + 1];
}
}
signed main(){
int n,m;
cin >> n >> m;
for (int i = 1;i <= n;i ++) cin >> a[i];
buildtree(1,1,n);
while (m --) {
int op,x,y,z;
cin >> op;
if (op == 1) {
cin >> x >> y >> z;
update(1,1,n,x,y,z);
} else {
cin >> x >> y;
cout << query(1,1,n,x,y) << endl;
}
}
return 0;
}