|
|
#include <bits/stdc++.h>
|
|
|
using namespace std;
|
|
|
|
|
|
typedef long long LL;
|
|
|
const int N = 100010;
|
|
|
|
|
|
int n, m;
|
|
|
int a[N];
|
|
|
struct Node {
|
|
|
int l, r;
|
|
|
LL sum, tag; // 区间总和,修改的数值(懒标记)
|
|
|
} tr[N << 2];
|
|
|
|
|
|
// 向祖先节点更新统计信息
|
|
|
void pushup(int u) {
|
|
|
tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum; // 向父节点更新sum和
|
|
|
}
|
|
|
|
|
|
// 父节点向子节点传递懒标记
|
|
|
void pushdown(int u) {
|
|
|
auto &root = tr[u], &ls = tr[u << 1], &rs = tr[u << 1 | 1];
|
|
|
if (root.tag) { // 如果存在懒标记
|
|
|
// tag传递到子段,子段的sum和需要按 区间长度*root.tag 进行增加
|
|
|
ls.tag += root.tag, ls.sum += (LL)(ls.r - ls.l + 1) * root.tag;
|
|
|
rs.tag += root.tag, rs.sum += (LL)(rs.r - rs.l + 1) * root.tag;
|
|
|
// 清除懒标记
|
|
|
root.tag = 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 构建
|
|
|
void build(int u, int l, int r) {
|
|
|
tr[u] = {l, r}; // 标记范围
|
|
|
if (l == r) { // 叶子
|
|
|
tr[u] = {l, r, a[l], 0}; // 区间内只有一个元素l(r),区间和为a[l],不需要记录向下的传递tag
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
int mid = (l + r) >> 1;
|
|
|
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r); // 左右儿子构建
|
|
|
pushup(u); // 通过左右儿子构建后,向祖先节点反馈统计信息变化
|
|
|
}
|
|
|
|
|
|
// 以u为根,在区间[l,r]之间全都增加v
|
|
|
void modify(int u, int l, int r, int v) {
|
|
|
if (tr[u].l >= l && tr[u].r <= r) { // 如果区间完整命中
|
|
|
tr[u].sum += (LL)(tr[u].r - tr[u].l + 1) * v; // 总和增加 = 区间长度*v
|
|
|
tr[u].tag += v; // 懒标记+v
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
pushdown(u); // 如果自己身上有旧的tag数值,在递归前需要将原tag值pushdown到子孙节点去
|
|
|
int mid = (tr[u].l + tr[u].r) >> 1;
|
|
|
if (l <= mid) modify(u << 1, l, r, v); // 与左区间有交集
|
|
|
if (r > mid) modify(u << 1 | 1, l, r, v); // 与右区间有交集
|
|
|
pushup(u); // 将结果的变更更新到祖先节点
|
|
|
}
|
|
|
|
|
|
// 关键的查询操作
|
|
|
LL query(int u, int l, int r) {
|
|
|
if (tr[u].l >= l && tr[u].r <= r) return tr[u].sum;
|
|
|
|
|
|
// 记住原则:有懒标记的区间修改,都是先pushdown消除掉懒标记,再分裂
|
|
|
pushdown(u);
|
|
|
|
|
|
int mid = tr[u].l + tr[u].r >> 1;
|
|
|
LL sum = 0;
|
|
|
if (l <= mid) sum = query(u << 1, l, r);
|
|
|
if (r > mid) sum += query(u << 1 | 1, l, r);
|
|
|
|
|
|
// 左查+ 右查 = 总和
|
|
|
return sum;
|
|
|
}
|
|
|
|
|
|
int main() {
|
|
|
// 加快读入
|
|
|
ios::sync_with_stdio(false), cin.tie(0);
|
|
|
cin >> n >> m;
|
|
|
for (int i = 1; i <= n; i++) cin >> a[i];
|
|
|
// 构建线段树
|
|
|
build(1, 1, n);
|
|
|
|
|
|
char op;
|
|
|
int l, r, d;
|
|
|
while (m--) {
|
|
|
cin >> op >> l >> r;
|
|
|
if (op == 'C') {
|
|
|
cin >> d;
|
|
|
modify(1, l, r, d); // 区间修改
|
|
|
} else
|
|
|
printf("%lld\n", query(1, l, r)); // 区间查询
|
|
|
}
|
|
|
return 0;
|
|
|
} |