/**************************************************************** 
 * Description: 
 线段树的构建与操作：
线段树用于处理区间操作，比如加法更新和区间和查询。通过递归地构建树，每个节点代表一个区间，并存储该区间内的和。
build函数用于构建线段树，push_up用于向上更新父节点的值。
延迟标记（懒标记）：

为了提高区间更新的效率，使用了懒标记技术。当执行一个区间更新操作时，如果该区间内的节点尚未被访问，标记会被推迟到真正需要访问这些节点的时候再进行更新。
区间更新和查询：

update函数用于更新指定区间内的值，同时利用懒标记技术延迟部分计算。
query函数用于查询指定区间的和，通过递归地访问相应的子区间，最终返回区间和。
 * Author: Alex Li
 * Date: 2024-08-19 22:12:23
 * LastEditTime: 2024-08-19 22:19:58
****************************************************************/


#include<iostream>
#define MAXN 1000001
#define ll long long
using namespace std;

unsigned ll n, m, a[MAXN], ans[MAXN<<2], tag[MAXN<<2];

// 获取左子节点的下标
ll ls(ll x) {
    return x << 1;
}

// 获取右子节点的下标
ll rs(ll x) {
    return x << 1 | 1;
}

// 读取输入数据
void scan() {
    cin >> n >> m;
    for (ll i = 1; i <= n; i++) {
        cin >> a[i];
    }
}

// 向上更新父节点的值
void push_up(ll p) {
    ans[p] = ans[ls(p)] + ans[rs(p)];
}

// 建立线段树
void build(ll p, ll l, ll r) {
    tag[p] = 0;  // 初始化懒标记
    if (l == r) {  // 叶子节点
        ans[p] = a[l];  // 直接赋值为对应位置的数组值
        return;
    }
    ll mid = (l + r) >> 1;
    build(ls(p), l, mid);  // 构建左子树
    build(rs(p), mid + 1, r);  // 构建右子树
    push_up(p);  // 向上更新当前节点的值
}

// 对区间进行延迟标记的更新
void f(ll p, ll l, ll r, ll k) {
    tag[p] = tag[p] + k;  // 更新懒标记
    ans[p] = ans[p] + k * (r - l + 1);  // 更新当前节点的值
}

// 向下传递懒标记
void push_down(ll p, ll l, ll r) {
    ll mid = (l + r) >> 1;
    f(ls(p), l, mid, tag[p]);  // 将懒标记传递给左子节点
    f(rs(p), mid + 1, r, tag[p]);  // 将懒标记传递给右子节点
    tag[p] = 0;  // 清除当前节点的懒标记
}

// 更新区间内的值
void update(ll nl, ll nr, ll l, ll r, ll p, ll k) {
    if (nl <= l && r <= nr) {  // 当前区间完全在更新范围内
        ans[p] += k * (r - l + 1);  // 更新当前区间的和
        tag[p] += k;  // 记录懒标记
        return;
    }
    push_down(p, l, r);  // 将懒标记下推到子节点
    ll mid = (l + r) >> 1;
    if (nl <= mid) update(nl, nr, l, mid, ls(p), k);  // 更新左子区间
    if (nr > mid) update(nl, nr, mid + 1, r, rs(p), k);  // 更新右子区间
    push_up(p);  // 更新当前节点的值
}

// 查询区间内的和
ll query(ll q_x, ll q_y, ll l, ll r, ll p) {
    ll res = 0;
    if (q_x <= l && r <= q_y) return ans[p];  // 当前区间完全在查询范围内
    ll mid = (l + r) >> 1;
    push_down(p, l, r);  // 将懒标记下推到子节点
    if (q_x <= mid) res += query(q_x, q_y, l, mid, ls(p));  // 查询左子区间
    if (q_y > mid) res += query(q_x, q_y, mid + 1, r, rs(p));  // 查询右子区间
    return res;
}

int main() {
    ll a1, b, c, d, e, f;
    scan();  // 读取输入
    build(1, 1, n);  // 建立线段树
    while (m--) {  // 处理每一个操作
        cin >> a1;
        switch (a1) {
            case 1: {
                cin >> b >> c >> d;
                update(b, c, 1, n, 1, d);  // 执行区间更新操作
                break;
            }
            case 2: {
                cin >> e >> f;
                cout << query(e, f, 1, n, 1) << endl;  // 执行区间查询操作
                break;
            }
        }
    }
    return 0;
}
