#include <algorithm>
#include <iostream>
#define int long long
#define size sizes
using namespace std ;
const int N = 1e7 ;
int n ;
int m ;
int input[N] ;
int size ;
int num[N] ;
int way, l, r, x ;
struct Node_tree {
int l, r ;
int maxn, sum ;
int lazy ;
} tree[4 * N + 5] ;
// 离散化配套的二分查找
int lower_b(int x[], int r, int k) {
int l = 1 ;
while(l <= r) {
int mid = (l + r) >> 1 ;
if(x[m] == k) return mid ;
if(k < x[m]) r = mid - 1 ;
else l = mid + 1 ;
}
return -1 ;
}
// 离散化
void Discretization() {
for(register int i = 1 ; i <= n ; i ++)
num[i] = input[i] ;
sort(num + 1, num + 1 + n) ;
size = unique(num + 1, num + n + 1) - num ;
/*也可以为:
size = 1 ;
for(register int i = 1 ; i <= n ; i ++)
if(sub[i] > sub[i - 1]) a[size ++] = a[i] ;
*/
for(register int i = 1 ; i <= n ; i ++)
input[i] = lower_bound(num + 1, num + n + 1, input[i]) - num ;
/*也可以为:
for(register int i = 1 ; i <= n ; i ++)
a[i] = lower_bound(a + 1, size, sub[i]) ;
*/
}
// 数据上传(更新父节点)
void push_up(int id) {
tree[id].sum = tree[id * 2].sum + tree[id * 2 + 1].sum ;
tree[id].maxn = max(tree[id * 2].maxn, tree[id * 2 + 1].maxn) ;
}
// 数据下传(传播懒标记)
void push_down(int id, int l, int r) {
if (tree[id].lazy != 0) { // 如果有懒标记
int mid = (l + r) >> 1 ;
// 更新左子树和右子树的lazy值
tree[id * 2].lazy += tree[id].lazy ;
tree[id * 2 + 1].lazy += tree[id].lazy ;
// 更新左子树和右子树的sum和maxn
tree[id * 2].sum += tree[id].lazy * (mid - l + 1) ;
tree[id * 2 + 1].sum += tree[id].lazy * (r - mid) ;
tree[id * 2].maxn += tree[id].lazy * (mid - l + 1) ;
tree[id * 2 + 1].maxn += tree[id].lazy * (r - mid) ;
// 清除懒标记
tree[id].lazy = 0;
}
}
// 建线段树
void build(int id, int l, int r) {
tree[id].l = l; tree[id].r = r ;
if (l == r) { // 叶子结点的特判
tree[id].sum = num[l] ;
tree[id].maxn = num[l] ;
} else {
int mid = (l + r) >> 1 ;
build(id * 2, l, mid) ; // 构建左子树
build(id * 2 + 1, mid + 1, r) ; // 构建右子树
push_up(id) ; // 更新当前节点的值
}
}
// 区间修改
void change(int id, int l, int r, int x) {
//当前到了编号为 id 的节点,要把 [l..r] 区间中的所有元素的值 +x
if (l <= tree[id].l && r >= tree[id].r) {// 当前节点的区间完全包含在需要修改的区间中
tree[id].sum += (tree[id].r - tree[id].l + 1) * x ; // 更新sum
tree[id].maxn += x ; // 更新 maxn
tree[id].lazy += x ; // 记录懒标记
return;
}
push_down(id, tree[id].l, tree[id].r) ; // 先下传懒标记
int mid = (tree[id].l + tree[id].r) >> 1 ;
if (l <= mid) change(id * 2, l, r, x) ; // 修改左子树
if (r > mid) change(id * 2 + 1, l, r, x) ; // 修改右子树
push_up(id) ; // 更新当前节点
}
// 区间查询
int query(int id, int l, int r) {
//当前到了编号为 id 的节点,查询 [l..r] 的和
if (l <= tree[id].l && r >= tree[id].r) return tree[id].sum ;// 当前节点的区间完全包含在查询的区间中
push_down(id, tree[id].l, tree[id].r) ; // 先下传懒标记
int mid = (tree[id].l + tree[id].r) >> 1 ;
int res = 0;
if (l <= mid) res += query(id * 2, l, r) ; // 查询左子树
if (r > mid) res += query(id * 2 + 1, l, r) ; // 查询右子树
return res;
}
signed main() {
cin >> n >> m ;
for (int i = 1 ; i <= n ; i ++)
cin >> input[i] ;
Discretization() ;
build(1, 1, n); // 构建线段树
for (int i = 1; i <= m; i++) {
cin >> way >> l >> r;
if (way == 1) {
cin >> x ;
change(1, l, r, x) ; // 区间加值
} else if (way == 2)
cout << query(1, l, r) << '\n' ; // 查询区间和
}
return 0 ;
}
感觉废了