给定一个序列,需要支持两种操作:

  1. 询问给定区间 [l,r] [l, r] 中的最大子段和
  2. 修改序列中某个元素的值

题解

最大子段和问题的最优复杂度显然是 O(n) O(n) 的 dp,但是我们要求的是某个区间中的最大子段和,并且需要支持对区间上的某个位置修改其值,所以我们用分治法来求,用线段树来维护信息。

我们考虑对于求解一个区间的最大子段和的分治做法,首先将其分为两个子区间。

整个大区间的最大子段和可能等于某一个小区间的最大子段和,但是也有可能存在最大子段和中的子段跨过区间中点的情况,所以我们需要左半边区间强制包含右端点的最大子段和,以及右半边区间强制包含左端点的最大子段和,这样将这两个加起来,得到大区间跨过区间中点的最大子段和,三者取最大即可。

对于线段树而言,我们对于每个节点都记录该区间的最大子段和,该区间包含左端点,包含右端点的最大子段和,具体实现见代码。

代码

#include <cstdio>
#include <cstring>
#include <climits>
#include <algorithm>
const int MAXN = 500000;
const int MAXM = 100000;
struct SegmentTree {
struct Node {
Node *lc, *rc;
int l, r, val;
int sum, lsum, rsum, maxSum;
Node() {}
Node(Node *lc, Node *rc, int l, int r) : lc(lc), rc(rc), l(l), r(r) {}
void update() {
sum = val;
if (lc) sum += lc->sum;
if (rc) sum += rc->sum;
lsum = rsum = sum;
if (lc) {
lsum = std::max(lsum, lc->lsum);
if (rc) lsum = std::max(lsum, lc->sum + rc->lsum);
}
if (rc) {
rsum = std::max(rsum, rc->rsum);
if (lc) rsum = std::max(rsum, rc->sum + lc->rsum);
}
maxSum = sum;
maxSum = std::max(maxSum, lsum);
maxSum = std::max(maxSum, rsum);
if (lc) maxSum = std::max(maxSum, lc->maxSum);
if (rc) maxSum = std::max(maxSum, rc->maxSum);
if (lc && rc) maxSum = std::max(maxSum, lc->rsum + rc->lsum);
}
void query(int l, int r, int &sum, int &lsum, int &rsum, int &maxSum) {
if (this->l > r || this->r < l) return;
else if (this->l >= l && this->r <= r) {
sum = this->sum;
lsum = this->lsum;
rsum = this->rsum;
maxSum = this->maxSum;
} else {
int mid = (this->l + this->r) >> 1;
if (r <= mid) return lc->query(l, r, sum, lsum, rsum, maxSum);
if (l >= mid + 1) return rc->query(l, r, sum, lsum, rsum, maxSum);
else {
int suml, lsuml, rsuml, maxSuml;
int sumr, lsumr, rsumr, maxSumr;
lc->query(l, r, suml, lsuml, rsuml, maxSuml);
rc->query(l, r, sumr, lsumr, rsumr, maxSumr);
maxSum = sum = suml + sumr;
lsum = std::max(lsuml, suml + lsumr);
rsum = std::max(rsumr, sumr + rsuml);
maxSum = std::max(maxSum, maxSuml);
maxSum = std::max(maxSum, maxSumr);
maxSum = std::max(maxSum, rsuml + lsumr);
}
}
}
void modify(int pos, int val) {
if (this->l > pos || this->r < pos) return;
else if (this->l == pos && this->r == pos) this->val = val, update();
else {
if (lc) lc->modify(pos, val);
if (rc) rc->modify(pos, val);
update();
}
}
} *root;
SegmentTree(int l, int r) {
root = build(l, r);
}
Node *build(int l, int r) {
if (l > r) return NULL;
else if (l == r) return new Node(NULL, NULL, l, r);
else {
int mid = (l + r) >> 1;
return new Node(build(l, mid), build(mid + 1, r), l, r);
}
}
void modify(int pos, int val) {
root->modify(pos, val);
}
int query(int l, int r) {
int sum, lsum, rsum, maxSum;
root->query(l, r, sum, lsum, rsum, maxSum);
return maxSum;
}
} *segt;
int main() {
int n, m;
scanf("%d %d", &n, &m);
segt = new SegmentTree(1, n);
for (int i = 1; i <= n; i++) {
int x;
scanf("%d", &x);
segt->modify(i, x);
}
for (int i = 0; i < m; i++) {
int k;
scanf("%d", &k);
if (k == 1) {
int l, r;
scanf("%d %d", &l, &r);
if (l > r) std::swap(l, r);
printf("%d\n", segt->query(l, r));
} else {
int pos, val;
scanf("%d %d", &pos, &val);
segt->modify(pos, val);
}
}
return 0;
}