Files
python/TangDou/AcWing/SegmentTree/243_XDS.cpp
HuangHai 1f397eca87 'commit'
2025-08-30 18:35:01 +08:00

94 lines
3.0 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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