题面
输出样例
5 3
1 2 -3 4 5
1 2 3
2 2 -1
1 3 2
输入样例
2
-1
题解
- 单点修改,区间查询,经典线段树问题,一般单点修改不会用到懒标记(pushdown操作),问题就会简单点
- 我们做线段树的题一般先确定节点中的属性,然后再做,那么节点中的属性有哪些,最基本的就是区间的左右端点 l , r 。 还有就是题中要求的最大连续字段和 lmax 。有了这三个,我们就要考虑能不能由子节点来更新出父节点的 lmax ,显然是不行的, 看图对于不跨区间的情况,我们只需要在左右儿子的lmax中去一个最大就好,但是对于跨区间来说,父节点的lmax应该是左儿子的最大后缀和+右儿子的最大前缀和
- 那么我们的节点属性就应该增加permax,sufmax ,那么对于新加的属性,我们能否通过子节点来更新呢,也需要分情况,如图所示,我们就又加入了属性sum(区间总和),对于父节点的区间总和,就等于左右儿子的区间总和,所以我们不需要再新加属性了,当然最大后缀也是一样的道理,这里就不说明了,到此我们节点的属性就全部更新完毕了。
- 只要确定了节点中的属性,其余我们就直接套模板就好,具体看码
代码
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 5e5 + 10;
int n, m;
int w[N];
struct Node {
int l, r; //左右端点
int tmax; //最大连续子段和
int premax; //最大前缀和
int sufmax; //最大后缀和
int sum; //区间和
} tr[N * 4];
//更新节点信息的函数
void pushup(Node &u, Node &l, Node &r) {
u.sum = l.sum + r.sum;
u.premax = max(l.premax, l.sum + r.premax);
u.sufmax = max(r.sufmax, r.sum + l.sufmax);
u.tmax = max(max(l.tmax, r.tmax), l.sufmax + r.premax);
}
//由子节点更新父节点的信息
void pushup(int u) {
pushup(tr[u], tr[u << 1], tr[u << 1 | 1]);
}
//建树
void build(int u, int l, int r) {
if (l == r) tr[u] = {
l, r, w[r], w[r], w[r], w[r]};
else {
tr[u] = {
l, r};
int mid = (l + r) >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
pushup(u);
}
}
//单点修改
void modify(int u, int x, int v) {
if (tr[u].l == x && tr[u].r == x) tr[u] = {
x, x, v, v, v, v};
else {
int mid = (tr[u].l + tr[u].r) >> 1;
if (x <= mid) modify(u << 1, x, v);
else modify(u << 1 | 1, x, v);
pushup(u);
}
}
//区间查询
Node query(int u, int l, int r) {
if (l <= tr[u].l && tr[u].r <= r) return tr[u];
else {
int mid = (tr[u].l + tr[u].r) >> 1;
if (r <= mid) return query(u << 1, l, r);
else if (l > mid) return query(u << 1 | 1, l, r);
else {
Node res;
auto left = query(u << 1, l, r);
auto right = query(u << 1 | 1, l, r);
pushup(res, left, right);
return res;
}
}
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) scanf("%d", &w[i]);
build(1, 1, n);
while (m--) {
int op, x, y;
cin >> op >> x >> y;
if (op == 1) {
if (x > y) swap(x, y);
cout << query(1, x, y).tmax << endl;
} else {
modify(1, x, y);
}
}
return 0;
}