题意
思路
- 单点修改比较好维护,但是区间连续子段和就比较难维护了,我们需要在结构提供维护一些间接条件,在这些间接条件的帮助下我们才能维护出最大连续字段和,我们需要在结构体中维护的条件如下 :
- 当前区间最大连续子段和:mx
- 当前区间的和:sum
- 当前区间的前缀最大值: lmx
- 当前区间的后缀最大值:rmx
- 维护关系如下图。
3. 注意区间最大连续子段和 mx 的产生有三种情况:
- 最大子段和只在左子区间中产生:l.mx
- 最大子段和只在有子区间中产生:r.mx
- 最大子段和横跨两个子区间 l,r:l.rmx + r.lmx
代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define ls (k << 1)
#define rs (k << 1 | 1)
const int N = 500005;
int n, m, a[N];
struct Tree
{
int l, r;
int sum, lmx, rmx, mx;
} tr[N * 4];
void push_up(Tree & u, Tree l, Tree r)
{
u.sum = l.sum + r.sum;
u.lmx = max(l.lmx, l.sum + r.lmx);
u.rmx = max(r.rmx, r.sum + l.rmx);
u.mx = max(max(l.mx, r.mx), l.rmx + r.lmx);
}
void build(int k, int l, int r)
{
tr[k] = {
l, r };
if (l == r)
{
tr[k] = {
l, r, a[l], a[l], a[l], a[l] };
return;
}
int md = (l + r) >> 1;
build(ls, l, md);
build(rs, md + 1, r);
push_up(tr[k], tr[ls], tr[rs]);
}
void update(int k, int x, int v)
{
if (tr[k].l == x && tr[k].r == x)
{
tr[k] = {
x, x, v, v, v, v };
return;
}
int md = (tr[k].l + tr[k].r) >> 1;
if (x <= md) update(ls, x, v);
else update(rs, x, v);
push_up(tr[k], tr[ls], tr[rs]);
}
Tree query(int k, int l, int r)
{
if (tr[k].l >= l && tr[k].r <= r) return tr[k];
int md = (tr[k].l + tr[k].r) >> 1;
if (r <= md) return query(ls, l, r);
else if (l > md) return query(rs, l, r);
else
{
Tree t;
push_up(t, query(ls, l, r), query(rs, l, r));
return t;
}
}
int main()
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i ++) scanf("%d", &a[i]);
build(1, 1, n);
int op, x, y;
while (m --)
{
scanf("%d %d %d", &op, &x, &y);
if (op == 1)
{
if (x > y) swap(x, y);
printf("%d\n", query(1, x, y).mx);
}
else
{
update(1, x, y);
}
}
return 0;
}