Acwing 245 - 你能回答这些问题吗
题目链接
给定长度为 N N N的序列 A A A,以及 M M M条指令。每条指令可能为以下两种之一:
- 1 x y 1\ x\ y 1 x y,查询区间 [ x , y ] [x,y] [x,y]中的最大连续子段和。
- 2 x y 2\ x\ y 2 x y,把 A [ x ] A[x] A[x]改成 y y y。
对于每个查询指令,输出一个整数表示答案。
对于线段树的每一个节点,维护对应区间的最大前缀、最大后缀、区间内的元素和、区间最大子段和。
struct Tree {
int l, r;
LL sum, pre, suf, mx;
}t[2000050];
push_up函数:每次更新完两个子区间后,要通过子区间的信息维护当前信息的内容。
- 区间元素和sum:直接取两个区间和的和即可。
- 区间最大前缀:取左区间最大前缀、左区间元素和+右区间最大前缀中的最大值。
- 区间最大后缀:取右区间最大后缀、右区间元素和+左区间最大后缀中的最大值。
- 区间最大子段和:取左、右区间最大子段和、左区间最大后缀+右区间最小前缀三者中的最大值。
void pu(int ni) {
t[ni].sum = t[ni << 1].sum + t[ni << 1 | 1].sum;
t[ni].pre = max(t[ni << 1].pre, t[ni << 1].sum + t[ni << 1 | 1].pre);
t[ni].suf = max(t[ni << 1 | 1].suf, t[ni << 1].suf + t[ni << 1 | 1].sum);
t[ni].mx = max({t[ni << 1].mx, t[ni << 1 | 1].mx, t[ni << 1].suf + t[ni << 1 | 1].pre});
}
建树:
注意维护的四个值的初始化。
void build_tree(int ni, int l, int r) {
t[ni].l = l; t[ni].r = r;
if (l == r) {
t[ni].sum = t[ni].pre = t[ni].suf = t[ni].mx = a[l];
return;
}
int mid = (l + r) >> 1;
build_tree(ni << 1, l, mid);
build_tree(ni << 1 | 1, mid + 1, r);
pu(ni);
}
更新操作:单点修改,所以没有懒标记,也不需要push_down函数。
单点修改后push_up即可。
void fix(int ni, int pos, int x) {
if (t[ni].l == t[ni].r and t[ni].l == pos) {
t[ni].sum = t[ni].pre = t[ni].suf = t[ni].mx = x;
return;
}
int mid = (t[ni].l + t[ni].r) >> 1;
if (pos <= mid) fix(ni << 1, pos, x);
else fix(ni << 1 | 1, pos, x);
pu(ni);
}
查询操作:查询操作稍微复杂一些,因为涉及到查询区间和当前区间的相对关系。
- 如果查询区间包含了当前区间,那么返回当前区间的全部四个信息。(为了方便起见,直接返回线段树的节点。)
- 如果查询区间完全在当前区间的左半区间,则只查询左半区间并返回所得节点信息。
- 如果查询区间完全在当前区间的右半区间,则只查询右半区间并返回所得节点信息。
- 如果查询区间横跨了左右区间,那么分别查询左右两个区间。由于是不断递归获得的信息,所以虽然查询了左右两个区间,但是获得的信息只有我们查询区间的信息。使用与pu函数相同的思想对查询结果进行push_up,将push_up出来的结果进行返回。
Tree query(int ni, int l, int r) {
if (l <= t[ni].l and t[ni].r <= r) {
return t[ni];
}
LL mid = (t[ni].l + t[ni].r) >> 1;
if (r <= mid) return query(ni << 1, l, r);
else if (mid < l) return query(ni << 1 | 1, l, r);
else {
Tree res, t1, t2;
t1 = query(ni << 1, l, r);
t2 = query(ni << 1 | 1, l, r);
res.sum = t1.sum + t2.sum;
res.pre = max(t1.pre, t1.sum + t2.pre);
res.suf = max(t2.suf, t1.suf + t2.sum);
res.mx = max({t1.mx, t2.mx, t1.suf + t2.pre});
return res;
}
}
Code:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int n, m;
int a[500050];
struct Tree {
int l, r;
LL sum, pre, suf, mx;
}t[2000050];
void pu(int ni) {
t[ni].sum = t[ni << 1].sum + t[ni << 1 | 1].sum;
t[ni].pre = max(t[ni << 1].pre, t[ni << 1].sum + t[ni << 1 | 1].pre);
t[ni].suf = max(t[ni << 1 | 1].suf, t[ni << 1].suf + t[ni << 1 | 1].sum);
t[ni].mx = max({t[ni << 1].mx, t[ni << 1 | 1].mx, t[ni << 1].suf + t[ni << 1 | 1].pre});
}
void build_tree(int ni, int l, int r) {
t[ni].l = l; t[ni].r = r;
if (l == r) {
t[ni].sum = t[ni].pre = t[ni].suf = t[ni].mx = a[l];
return;
}
int mid = (l + r) >> 1;
build_tree(ni << 1, l, mid);
build_tree(ni << 1 | 1, mid + 1, r);
pu(ni);
}
void fix(int ni, int pos, int x) {
if (t[ni].l == t[ni].r and t[ni].l == pos) {
t[ni].sum = t[ni].pre = t[ni].suf = t[ni].mx = x;
return;
}
int mid = (t[ni].l + t[ni].r) >> 1;
if (pos <= mid) fix(ni << 1, pos, x);
else fix(ni << 1 | 1, pos, x);
pu(ni);
}
Tree query(int ni, int l, int r) {
if (l <= t[ni].l and t[ni].r <= r) {
return t[ni];
}
LL mid = (t[ni].l + t[ni].r) >> 1;
if (r <= mid) return query(ni << 1, l, r);
else if (mid < l) return query(ni << 1 | 1, l, r);
else {
Tree res, t1, t2;
t1 = query(ni << 1, l, r);
t2 = query(ni << 1 | 1, l, r);
res.sum = t1.sum + t2.sum;
res.pre = max(t1.pre, t1.sum + t2.pre);
res.suf = max(t2.suf, t1.suf + t2.sum);
res.mx = max({t1.mx, t2.mx, t1.suf + t2.pre});
return res;
}
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
}
build_tree(1, 1, n);
for (int i = 1; i <= m; ++i) {
int op, x, y;
cin >> op >> x >> y;
if (op == 1) {
if (x > y) swap(x, y);
cout << query(1, x, y).mx << "\n";
}
else {
fix(1, x, y);
}
}
return 0;
}