# 「学习笔记」线段树标记永久化

## 具体操作

inline void modify(int u, int l, int r, int lr, int rr, ll c) {
t[u].val += (rr - lr + 1) * c;
if (lr == l && r == rr) {
t[u].laz += c;
return ;
}
if (rr <= mid)	modify(ls, l, mid, lr, rr, c);
else if (lr > mid)	modify(rs, mid + 1, r, lr, rr, c);
else {
modify(ls, l, mid, lr, mid, c);
modify(rs, mid + 1, r, mid + 1, rr, c);
}
}


inline ll query(int u, int l, int r, int lr, int rr, ll add) {
if (lr == l && r == rr) {
return t[u].val + add * t[u].len;
}
ll sum = 0;
if (rr <= mid) {
sum = query(ls, l, mid, lr, rr, add + t[u].laz);
}
else if (lr > mid) {
sum = query(rs, mid + 1, r, lr, rr, add + t[u].laz);
}
else {
sum = query(ls, l, mid, lr, mid, add + t[u].laz)
+ query(rs, mid + 1, r, mid + 1, rr, add + t[u].laz);
}
return sum;
}


## 总结

1. 码量小，不用写 pushdownpushup
2. 在可持久化线段树上应用该技巧能做到区间修改的效果。

1. 适用范围有限,只有当求的东西满足区间贡献独立。比如区间加法。
区间最大值就无法标记永久化。
2. 多标记好像也不适用。

## 例题

【模板】线段树 1

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (u << 1)
#define rs (u << 1 | 1)
#define mid ((l + r) >> 1)

const int N = 1e5 + 5;

int n, m;

struct seg_tree {
int len;
ll val, laz;
} t[N << 2];

inline void build(int u, int l, int r) {
t[u].len = r - l + 1, t[u].laz = 0;
if (l == r) {
cin >> t[u].val;
return ;
}
build(ls, l, mid);
build(rs, mid + 1, r);
t[u].val = t[ls].val + t[rs].val;
}

inline void modify(int u, int l, int r, int lr, int rr, ll c) {
t[u].val += (rr - lr + 1) * c;
if (lr == l && r == rr) {
t[u].laz += c;
return ;
}
if (rr <= mid)	modify(ls, l, mid, lr, rr, c);
else if (lr > mid)	modify(rs, mid + 1, r, lr, rr, c);
else {
modify(ls, l, mid, lr, mid, c);
modify(rs, mid + 1, r, mid + 1, rr, c);
}
}

inline ll query(int u, int l, int r, int lr, int rr, ll add) {
if (lr == l && r == rr) {
return t[u].val + add * t[u].len;
}
ll sum = 0;
if (rr <= mid) {
sum = query(ls, l, mid, lr, rr, add + t[u].laz);
}
else if (lr > mid) {
sum = query(rs, mid + 1, r, lr, rr, add + t[u].laz);
}
else {
sum = query(ls, l, mid, lr, mid, add + t[u].laz)
+ query(rs, mid + 1, r, mid + 1, rr, add + t[u].laz);
}
return sum;
}

int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n >> m;
build(1, 1, n);
for (int i = 1, op, x, y; i <= m; ++ i) {
cin >> op >> x >> y;
if (op == 1) {
ll k;
cin >> k;
modify(1, 1, n, x, y, k);
}
else {
cout << query(1, 1, n, x, y, 0) << '\n';
}
}
return 0;
}

posted @ 2023-05-17 21:57  yi_fan0305  阅读(196)  评论(2编辑  收藏  举报