You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

94 lines
3.0 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#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;
}