跟着董晓老师写的线段树板子题:

代码如下:
#define ll long long
#define lc p<<1 // 左孩子节点编号:p * 2
#define rc p<<1|1 // 右孩子节点编号:p * 2 + 1
using namespace std;
const int N = 1e5 + 5; // 数据范围,根据题目调整
// 线段树节点结构
struct Node {
int l, r; // 当前节点代表的区间 [l, r]
ll sum; // 当前区间的和
ll add; // 懒标记,用于延迟更新区间操作
} tree[N << 2]; // 线段树数组,大小开4倍防止越界
ll w[N]; // 原始数组,存储初始数据
// 向上更新:用左右子节点的和更新当前节点的和
void pushup(int p) {
// 当前节点的和 = 左子树的和 + 右子树的和
tree[p].sum = tree[lc].sum + tree[rc].sum;
}
// 向下传递懒标记:将当前节点的懒标记传递给左右子节点
void pushdown(int p) {
if (tree[p].add) { // 如果当前节点有未传递的懒标记
// 更新左子节点的和:区间长度 * 懒标记值
tree[lc].sum += tree[p].add * (tree[lc].r - tree[lc].l + 1);
// 更新右子节点的和:区间长度 * 懒标记值
tree[rc].sum += tree[p].add * (tree[rc].r - tree[rc].l + 1);
// 传递懒标记到左子节点
tree[lc].add += tree[p].add;
// 传递懒标记到右子节点
tree[rc].add += tree[p].add;
// 清除当前节点的懒标记
tree[p].add = 0;
}
}
// 构建线段树
// p:当前节点编号,l:当前区间左端点,r:当前区间右端点
void build(ll p, ll l, ll r) {
// 初始化当前节点的区间、和、懒标记
tree[p] = {l, r, w[l], 0};
if (l == r) return; // 叶子节点,直接返回
int mid = (l + r) >> 1; // 计算区间中点
build(lc, l, mid); // 递归构建左子树
build(rc, mid + 1, r); // 递归构建右子树
pushup(p); // 向上更新当前节点的和
}
// 区间更新:将区间 [x, y] 的每个数加上 k
// p:当前节点编号,x,y:目标区间,k:增量
void update(int p, int x, int y, ll k) {
// 如果当前节点区间完全包含在 [x, y] 中
if (x <= tree[p].l && tree[p].r <= y) {
// 更新当前节点的和:区间长度 * k
tree[p].sum += (tree[p].r - tree[p].l + 1) * k;
// 记录懒标记,延迟更新子节点
tree[p].add += k;
return;
}
pushdown(p); // 否则,先传递懒标记到子节点
int m = (tree[p].l + tree[p].r) >> 1; // 计算区间中点
// 如果目标区间与左子树区间有交集,递归更新左子树
if (x <= m) update(lc, x, y, k);
// 如果目标区间与右子树区间有交集,递归更新右子树
if (y > m) update(rc, x, y, k);
pushup(p); // 向上更新当前节点的和
}
// 区间查询:查询区间 [ql, qr] 的和
// p:当前节点编号,ql,qr:查询区间
ll query(ll p, ll ql, ll qr) {
// 如果当前节点区间完全包含在 [ql, qr] 中,直接返回当前节点的和
if (ql <= tree[p].l && tree[p].r <= qr) {
return tree[p].sum;
}
pushdown(p); // 否则,先传递懒标记到子节点
ll m = (tree[p].l + tree[p].r) >> 1; // 计算区间中点
ll sum = 0;
// 如果查询区间与左子树区间有交集,递归查询左子树
if (ql <= m) sum += query(lc, ql, qr);
// 如果查询区间与右子树区间有交集,递归查询右子树
if (qr > m) sum += query(rc, ql, qr);
return sum; // 返回查询区间的和
}
int main() {
ios::sync_with_stdio(false); // 加速输入输出
cin.tie(0);
int n, m;
cin >> n >> m; // 读入数据规模 n 和操作数 m
// 读入原始数组
for (int i = 1; i <= n; i++) {
cin >> w[i];
}
// 构建线段树,根节点编号为 1,区间为 [1, n]
build(1, 1, n);
// 处理 m 个操作
for (int i = 1; i <= m; i++) {
int op;
cin >> op; // 读入操作类型
if (op == 1) { // 区间更新操作:将 [x, y] 的每个数加上 k
ll x, y, k;
cin >> x >> y >> k;
update(1, x, y, k);
} else { // 区间查询操作:查询 [x, y] 的和
ll x, y;
cin >> x >> y;
cout << query(1, x, y) << endl;
}
}
return 0;
}``