用c++做线段树 (1)数列中某连续一段全部+1 (2)求数列中某连续一段的最小值,并输出这个值
时间: 2024-05-04 20:18:54 浏览: 34
线段树初步(C++)
下面是使用 C++ 实现的线段树解法:
```cpp
#include <iostream>
#include <cstdio>
using namespace std;
const int MAXN = 5e5 + 5;
int n, m, a[MAXN];
struct Node {
int l, r;
int sum, minn;
int add;
} tree[MAXN << 2];
void pushup(int p) {
tree[p].sum = tree[p << 1].sum + tree[p << 1 | 1].sum;
tree[p].minn = min(tree[p << 1].minn, tree[p << 1 | 1].minn);
}
void pushdown(int p) {
if (tree[p].add) {
tree[p << 1].add += tree[p].add;
tree[p << 1 | 1].add += tree[p].add;
tree[p << 1].sum += (tree[p << 1].r - tree[p << 1].l + 1) * tree[p].add;
tree[p << 1 | 1].sum += (tree[p << 1 | 1].r - tree[p << 1 | 1].l + 1) * tree[p].add;
tree[p << 1].minn += tree[p].add;
tree[p << 1 | 1].minn += tree[p].add;
tree[p].add = 0;
}
}
void build(int p, int l, int r) {
tree[p].l = l;
tree[p].r = r;
if (l == r) {
tree[p].sum = a[l];
tree[p].minn = a[l];
return;
}
int mid = (l + r) >> 1;
build(p << 1, l, mid);
build(p << 1 | 1, mid + 1, r);
pushup(p);
}
void update_add(int p, int l, int r, int k) {
if (tree[p].l >= l && tree[p].r <= r) {
tree[p].add += k;
tree[p].sum += (tree[p].r - tree[p].l + 1) * k;
tree[p].minn += k;
return;
}
pushdown(p);
int mid = (tree[p].l + tree[p].r) >> 1;
if (l <= mid) update_add(p << 1, l, r, k);
if (r > mid) update_add(p << 1 | 1, l, r, k);
pushup(p);
}
int query_min(int p, int l, int r) {
if (tree[p].l >= l && tree[p].r <= r) {
return tree[p].minn;
}
pushdown(p);
int mid = (tree[p].l + tree[p].r) >> 1;
int res = 0x3f3f3f3f;
if (l <= mid) res = min(res, query_min(p << 1, l, r));
if (r > mid) res = min(res, query_min(p << 1 | 1, l, r));
return res;
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
build(1, 1, n);
while (m--) {
int op, l, r, k;
scanf("%d%d%d", &op, &l, &r);
if (op == 1) {
scanf("%d", &k);
update_add(1, l, r, k);
} else {
printf("%d\n", query_min(1, l, r));
}
}
return 0;
}
```
对于区间加,我们需要维护四个信息:区间和、区间最小值、区间左端点被加的值、区间右端点被加的值。对于区间加的修改操作,我们需要将左右子树的区间加信息加上该节点的区间加信息,并且更新左右子树的区间和、区间最小值。对于区间查询,如果当前节点的区间被完全包含,我们直接返回该节点的区间最小值即可,否则我们需要将查询操作继续下传到左右子树。
对于区间最小值,我们需要维护区间最小值。对于区间最小值的查询,如果当前节点的区间被完全包含,我们直接返回该节点的区间最小值即可,否则我们需要将查询操作继续下传到左右子树。
时间复杂度:$O(m \log n)$
空间复杂度:$O(n \log n)$
阅读全文