线段树维护区间最大子段和

问题描述

给定一个序列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;
}
posted @ 2024-10-10 19:18  clockleaf  阅读(274)  评论(0)    收藏  举报