OI 里有许多这类问题
线段树是解决这类问题的一大利器。
给你一个序列
给你一个序列
给你一个序列
chmin 里,ch 表示 change。
给你一个序列
每个非叶子节点都有两个孩子。
性质:有
线段树是一种支持
的数据结构。
一个长为
线段树的每个节点对应序列的一段;每个节点维护它所对应的那一段的某些信息。
节点
线段树是高度平衡的满二叉树:每个节点的左右孩子的高度相差不超过
除了最后一层外,每一层都是满的。
一个序列的线段树的结构完全由序列长度决定。长度为
有
令
考虑具有
显然,当
趋近于
设
给你一个长为
const int maxn = 5e5 + 5;
int a[maxn];
int tree[4 * maxn];
// 节点x对应的区间:[l, r]
void build(int x, int l, int r) {
if (l == r) {
tree[x] = a[l];
return;
}
int m = (l + r) / 2;
build(x * 2, l, m);
build(x * 2 + 1, m + 1, r);
tree[x] = min(tree[x * 2], tree[x * 2 + 1]);
}
// build(1, 1, n)
// 节点x对应的区间:[l, r],查询区间:[ql, qr]
int query(int x, int l, int r, int ql, int qr) {
if (r < ql || qr < l) return 1e9 + 5;
if (ql <= l && r <= qr) return tree[x];
int m = (l + r) / 2;
return min(query(x * 2, l, m, ql, qr),
query(x * 2 + 1, m + 1, r, ql, qr));
}
// query(1, 1, 10, 3, 9)
// 把 a[p] 改成 v
void set(int x, int l, int r, int p, int v) {
if (!(l <= p && p <= r)) return;
if (l == r) {
tree[x] = v;
return;
}
int m = (l + r) / 2;
set(x * 2, l, m, p, v);
set(x * 2 + 1, m + 1, r, p, v);
tree[x] = min(tree[x * 2], tree[x * 2 + 1]);
}
// set(1, 1, 10, 2, 5)
给你一个长为
给定长为
const int maxn = 5e5 + 5;
long long tree[4 * maxn];
void add(int x, int l, int r, int ql, int qr, int v) {
if (qr < l || r < ql) return;
if (ql <= l && r <= qr) {
tree[x] += v;
return;
}
int m = (l + r) / 2;
add(x * 2, l, m, ql, qr, v);
add(x * 2, m + 1, r, ql, qr, v);
}
long long get(int x, int l, int r, int p) {
if (!(l <= p && p <= r)) return 0;
if (l == r) return tree[x];
int m = (l + r) / 2;
return tree[x] + get(x * 2, l, m, p)
+ get(x * 2 + 1, m + 1, r, p);
}
给定长为
对序列
affine 1 7 3 9
affine 2 8 4 7
对序列
affine 1 7 3 9
affine 2 8 4 7
给定长为
给你
给你
[洛谷P3865](https://www.luogu.com.cn/problem/P3865)