线段树维护区间最大子段和
问题描述
给定一个序列a{1}, a{2}, a{3}, ... , a{n},如何求出该序列的最大子段和?(询问的区间个数为m)
分析
解决方案:
- 暴力统计:对于每一个区间[l, r],每一次选定一个子段的起点,然后枚举子段的长度,时间复杂度为
O(mn^{2})。 - 动态规划:我们一次性算出所有的区间的最大子段和,然后直接询问答案。我们规定:
- ls:表示区间紧靠左端点的子段的最大和
- rs:表示区间紧靠右端点的子段的最大和
- ms:表示区间子段的最大和
- s:表示区间子段和
对于一个区间[l, r],将它一分为二,假设已经得到左区间和右区间的信息,那么对于这个区间而言:
-
对于ls:由两个选择,选择左区间的ls,或是选择左区间的子段和加上右区间的ls
-
对于rs:原理同ls
-
对于ms:由三个选择,选择左区间的ms,或是选择右区间的ms,或是选择左区间的rs加上右区间的ls
-
对于s:左区间的s加上右区间的s
下推代码
struct node {
int ls, rs, sum, ms;
}trss[N << 2];
inline void pushup(int root) {
tree[root].sum = tree[root << 1].sum + tree[root << 1 | 1].sum;
tree[root].ls = max(tree[root << 1].ls, tree[root << 1].sum + tree[root << 1 | 1].ls);
tree[root].rs = max(tree[root << 1 | 1].rs, tree[root << 1 | 1].sum + tree[root << 1].rs);
tree[root].ms = max(tree[root << 1].lr + tree[root << 1 | 1].rs, max(tree[root << 1].ms, tree[root << 1 | 1].ms));
}
题目1
GSS3 - Can you answer these queries III - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
洛谷的测试点好像炸了,数据库无法链接
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const int N = 1e5 + 5;
struct node {
int ls, rs, ms, val;
}tree[N << 2];
int a[N];
void pushup(int rt) {
tree[rt].val = tree[rt << 1].val + tree[rt << 1 | 1].val;
tree[rt].ls = max(tree[rt << 1].ls, tree[rt << 1].val + tree[rt << 1 | 1].ls);
tree[rt].rs = max(tree[rt << 1 | 1].rs, tree[rt << 1 | 1].val + tree[rt << 1].rs);
tree[rt].ms = max(tree[rt << 1].ls + tree[rt << 1 | 1].rs, max(tree[rt << 1].ms, tree[rt << 1 | 1].ms));
}
void bt(int l, int r, int rt) {
if (l == r) {
tree[rt].ls = a[l];
tree[rt].rs = a[l];
tree[rt].ms = a[l];
tree[rt].val = a[l];
return ;
}
int mid = l + r >> 1;
bt(l, mid, rt << 1);
bt(mid + 1, r, rt << 1 | 1);
pushup(rt);
}
void update(int l, int r, int rt, int pos, int val) {
if (l == r) {
tree[rt].ls = val;
tree[rt].rs = val;
tree[rt].ms = val;
tree[rt].val = val;
return ;
}
int mid = l + r >> 1;
if (pos <= mid) update(l, mid, rt << 1, pos, val);
else update(mid + 1, r, rt << 1 | 1, pos, val);
pushup(rt);
}
node query(int l, int r, int rt, int L, int R) {
if (L <= l && r <= R)
return tree[rt];
node x = {-inf, -inf, -inf, -inf};
node y = {-inf, -inf, -inf, -inf};
node z = {-inf, -inf, -inf, -inf};
int mid = l + r >> 1;
if (L <= mid) x = query(l, mid, rt << 1, L, R);
if (R > mid) y = query(mid + 1, r, rt << 1 | 1, L, R);
z.val = x.val + y.val;
z.ls = max(x.ls, x.val + y.ls);
z.rs = max(y.rs, y.val + x.rs);
z.ms = max(x.ls + y.rs, max(x.ms, y.ms));
return z;
}
void solve() {
int n;
cin >> n;
for (int i = 1; i <= n; ++i) cin >> a[i];
bt(1, n, 1);
int q;
cin >> q;
while (q--) {
int op, x, y;
cin >> op >> x >> y;
if (op == 0) {
update(1, n, 1, x, y);
}
else {
node ans = query(1, n, 1, x, y);
cout << max(ans.ms, max(ans.ls, ans.rs)) << endl;
}
}
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
int _ = 1;
// cin >> _;
while (_--) solve();
return 0;
}
题目2
0龙骑士军团【算法赛】 - 蓝桥云课 (lanqiao.cn)
线段树部分是模板,最后还需要进行数据处理
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const int N = 2e5 + 5;
ll a[N], sum[N];
struct node {
ll val, lm, rm;
}tree[N << 2];
void pushup(int root) {
tree[root].val = tree[root << 1].val + tree[root << 1 | 1].val;
tree[root].lm = max(tree[root << 1].lm, tree[root << 1].val + tree[root << 1 | 1].lm);
tree[root].rm = max(tree[root << 1 | 1].rm, tree[root << 1 | 1].val + tree[root << 1].rm);
}
void bt(int l, int r, int root) {
if (l == r) {
tree[root].val = a[l];
if (a[l] > 0) tree[root].lm = tree[root].rm = a[l];
return ;
}
int mid = l + r >> 1;
bt(l, mid, root << 1);
bt(mid + 1, r, root << 1 | 1);
pushup(root);
}
node query(int L, int R, int l, int r, int root) {
if (R < L)
return node({0, 0, 0});
if (L <= l && r <= R)
return tree[root];
int mid = l + r >> 1;
node n1({0, 0, 0}), n2({0, 0, 0});
if (L <= mid)
n1 = query(L, R, l, mid, root << 1);
if (R >= mid + 1)
n2 = query(L, R, mid + 1, r, root << 1 | 1);
return node({
n1.val + n2.val,
max(n1.lm, n1.val + n2.lm),
max(n2.rm, n2.val + n1.rm)
});
}
void solve() {
int n, q;
cin >> n >> q;
for (int i = 1; i <= n; ++i) cin >> a[i], sum[i] = sum[i - 1] + a[i];
bt(1, n, 1);
while (q--) {
int a, b, c, d;
cin >> a >> b >> c >> d;
ll s1 = query(a, b - 1, 1, n, 1).rm;
ll s2 = query(c + 1, d, 1, n, 1).lm;
cout << s1 + s2 + sum[c] - sum[b - 1] << endl;
}
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
int _ = 1;
// cin >> _;
while (_--) solve();
return 0;
}

浙公网安备 33010602011771号