线段树模板
本篇对应源码见仓库
solutions/xcpc/algorithm/ds/segment-tree/。
模板一
特点:
- 单点更新,区间更新
push_down、push_up- 区间查询
- 重载了两个
update与一个query
使用时注意:
i是节点编号,从 1 开始l, r是区间端点,默认从 0 开始,如果要修改,需要修改build为build(i, 1, n)
template<class T>
struct segmentTree {
struct Node {
int l, r;
T sum;
T lazy;
};
int n;
vector<Node> tr;
segmentTree(int _n) {
init(vector<T> (_n));
}
segmentTree(vector<T> a) {
init(a);
}
void init(vector<T> a) {
n = a.size();
tr.resize(n << 2, {});
function<void(int, int, int)> build = [&](int i, int l, int r) -> void {
tr[i].l = l, tr[i].r = r;
if(l == r) {
tr[i].sum = a[l];
return;
}
int mid = l + ((r - l) >> 1);
build(i << 1, l, mid);
build(i << 1 | 1, mid + 1, r);
push_up(i);
};
build(1, 0, n - 1);
}
void push_up(int i) {
tr[i].sum = tr[i << 1].sum + tr[i << 1 | 1].sum;
}
void push_down(int i) {
if(tr[i].lazy != 0) {
int l = tr[i].l, r = tr[i].r;
int mid = l + ((r - l) >> 1);
tr[i << 1].sum += tr[i].lazy * (mid - tr[i << 1].l + 1);
tr[i << 1].lazy += tr[i].lazy;
tr[i << 1 | 1].sum += tr[i].lazy * (tr[i << 1 | 1].r - mid);
tr[i << 1 | 1].lazy += tr[i].lazy;
tr[i].lazy = 0;
}
}
void update1(int i, int ind, T val) {
int l = tr[i].l, r = tr[i].r;
if(l == r) {
tr[i].sum += val;
return;
}
int mid = l + ((r - l) >> 1);
if(ind <= mid) update1(i << 1, ind, val);
else update1(i << 1 | 1, ind, val);
push_up(i);
}
void update2(int i, int ul, int ur, T val) {
int l = tr[i].l, r = tr[i].r;
if(r < ul || l > ur) return;
if(ul <= l && r <= ur) {
// 打懒标记,无需再往后更新
tr[i].sum += val * ((r - l) + 1);
tr[i].lazy += val;
return;
}
push_down(i);
update2(i << 1, ul, ur, val);
update2(i << 1 | 1, ul, ur, val);
push_up(i);
}
T query(int i, int ql, int qr) {
int l = tr[i].l, r = tr[i].r;
if(r < ql || l > qr) return 0;
if(ql <= l && r <= qr) return tr[i].sum;
push_down(i);
return query(i << 1, ql, qr) + query(i << 1 | 1, ql, qr);
}
void update(int ind, T val) {
update1(1, ind, val);
}
void update(int ul, int ur, T val) {
update2(1, ul, ur, val);
}
T query(int ql, int qr) {
return query(1, ql, qr);
}
};
模板二
特点:
- 有两种区间修改操作:\(+,\ *\)
- 所以对应两个懒标记
push_down时都先处理 \(*\) ,然后处理 \(+\) (包括 \(sum,\ mul,\ add\))
template<class T>
struct segmentTree {
struct Node {
int l, r;
T sum;
T mul = 1, add = 0;
};
int n;
vector<Node> tr;
int mod;
segmentTree(int _n) {
init(vector<T> (_n));
}
segmentTree(vector<T> a, int p = MOD) {
mod = p;
init(a);
}
void init(vector<T> a) {
n = a.size();
tr.resize(n << 2);
function<void(int, int, int)> build = [&](int i, int l, int r) -> void {
tr[i].l = l, tr[i].r = r;
if(l == r) {
tr[i].sum = a[l] % mod;
return;
}
int mid = l + (r - l >> 1);
build(i << 1, l, mid);
build(i << 1 | 1, mid + 1, r);
push_up(i);
};
build(1, 0, n - 1);
}
void push_up(int i) {
tr[i].sum = tr[i << 1].sum + tr[i << 1 | 1].sum;
tr[i].sum %= mod;
}
void push_down(int i) {
if(tr[i].add != 0 || tr[i].mul != 1) {
int l = tr[i].l, r = tr[i].r;
T mul = tr[i].mul, add = tr[i].add;
int mid = l + (r - l >> 1);
tr[i << 1].sum = (tr[i << 1].sum * mul % mod + add * (mid - l + 1) % mod) % mod;
tr[i << 1].mul = tr[i << 1].mul * mul % mod;
tr[i << 1].add = (tr[i << 1].add * mul % mod + add) % mod;
tr[i << 1 | 1].sum = (tr[i << 1 | 1].sum * mul % mod + add * (r - mid) % mod) % mod;
tr[i << 1 | 1].mul = tr[i << 1 | 1].mul * mul % mod;
tr[i << 1 | 1].add = (tr[i << 1 | 1].add * mul % mod + add) % mod;
tr[i].mul = 1;
tr[i].add = 0;
}
}
// void update1(int i, int ind, T val) {
// int l = tr[i].l, r = tr[i].r;
// if(l == r) {
// tr[i].sum += val;
// return;
// }
// int mid = l + (r - l >> 1);
// if(ind <= mid) update1(i << 1, ind, val);
// else update1(i << 1 | 1, ind, val);
// push_up(i);
// }
void update2(int i, int ul, int ur, T val, int op) {
int l = tr[i].l, r = tr[i].r;
if(r < ul || l > ur) return;
if(ul <= l && r <= ur) {
// 打懒标记,无需再往后更新
if(op == 1) {
tr[i].sum = tr[i].sum * val % mod;
tr[i].mul = tr[i].mul * val % mod;
tr[i].add = tr[i].add * val % mod;
} else if(op == 2) {
tr[i].sum = (tr[i].sum + val * (r - l + 1)) % mod;
tr[i].add = (tr[i].add + val ) % mod;
}
return;
}
push_down(i);
int mid = l + (r - l >> 1);
update2(i << 1, ul, ur, val, op);
update2(i << 1 | 1, ul, ur, val, op);
push_up(i);
}
T query(int i, int ql, int qr) {
int l = tr[i].l, r = tr[i].r;
if(r < ql || l > qr) return 0;
if(ql <= l && r <= qr) return tr[i].sum;
push_down(i);
return (query(i << 1, ql, qr) + query(i << 1 | 1, ql, qr)) % mod;
}
void update1(int ind, T val) {
update1(1, ind, val);
}
void update2(int ul, int ur, T val, int op) {
update2(1, ul, ur, val, op);
}
T query(int ql, int qr) {
return query(1, ql, qr);
}
};
signed main() {
IOS;
int n, q, m;
cin >> n >> q >> m;
vector<ll> arr(n);
fer(i, 0, n) cin >> arr[i];
segmentTree seg(arr, m);
while(q--) {
int op;
cin >> op;
if(op == 3) {
int x, y;
cin >> x >> y;
cout << seg.query(x - 1, y - 1) << '\n';
} else {
int x, y, k;
cin >> x >> y >> k;
seg.update2(x - 1, y - 1, k, op);
}
}
return 0;
}

浙公网安备 33010602011771号