SP1716 GSS3 - Can you answer these queries III (线段树维护最大连续子段和)

题目大意:

    给定数列A以及M条指令      "1 x y" 查询[x, y]中的最大连续子段和 "2 x y"把A[x] 改成y

单点修改的操作不再赘述 对于维护最大连续子段和的思路如下:

先从二叉树的视角考虑一下线段树中所有的情况:

tmax为最大连续子段和 最大前缀和为lmax 最大后缀和为rmax

1. 只需要递归左子区间或只需要递归右子区间

tmax = max (tmax, left_son)

 

 tmax = max(tmax, right_son)

 2.区间横跨mid(不与端点重合)时, 则需要同时递归左右子区间

此时还需维护左子区间的最大后缀和以及右子区间的最大前缀和

此时横跨左右子区间的最大子段和 = 左子区间的最大后缀和 + 右子区间的最大前缀和

 

tmax = max(tmax, left_son.rmax + right_son.lmax)

3.计算前缀/后缀

 

 tmax = max(tmax, left_son.sum + right_son.lmax)

4.完全覆盖该区间

  直接返回即可

 由此可知 线段树结构体中需要维护端点信息l和r,  最大前缀和lmax 最大后缀和rmax 当前区间和sum

线段树思想中有一点很关键, 就是要找到所有需要维护的信息应对各个情况, 需要让结构体中的信息具有完备性

查询时为了简化操作 用pushup更新并返回结构体

完整代码如下:

/*
 * @Author: Hellcat
 * @Date: 2020-03-10 14:15:14
 */
#include <bits/stdc++.h>
using namespace std;

const int N = 5e4 + 10;

int n, m, a[N];
struct node {
    int l, r;
    int tmax; // 最大连续子段和
    int lmax; // 最大前缀和
    int rmax; // 最大后缀和
    int sum;  // 区间[l, r]中的最大值
}tr[N<<2];

void pushup(node &u, node &l, node &r) {
    u.sum = l.sum + r.sum;
    u.lmax = max(l.lmax, l.sum + r.lmax);
    u.rmax = max(r.rmax, r.sum + l.rmax);
    u.tmax = max(max(l.tmax, r.tmax), l.rmax + r.lmax);
}

void pushup(int u) {
    pushup(tr[u], tr[u<<1], tr[u<<1 | 1]);
}

void build(int u, int l, int r) {
    tr[u] = {l, r, a[r], a[r], a[r], a[r]};
    if(l == r) return;
    int mid = (l + r) >> 1;
    build(u<<1, l, mid);
    build(u<<1 | 1, mid + 1, r);
    pushup(u);
}

void modify(int u, int x, int v) {
    if(tr[u].l == tr[u].r) { tr[u] = {x, x, v, v, v, v}; return; }
    int mid = (tr[u].l + tr[u].r) >> 1;
    if(x <= mid) modify(u << 1, x, v);
    else modify(u << 1 | 1, x, v);
    pushup(u);
}

node query(int u, int l, int r) {
    if(l <= tr[u].l && tr[u].r <= r) return tr[u];
    int mid = (tr[u].l + tr[u].r) >> 1;
    if(r <= mid) return query(u << 1, l, r);
    if(l > mid) return query(u << 1 | 1, l, r);
    auto left = query(u << 1, l, r);
    auto right = query(u << 1 | 1, l, r);
    node res;
    pushup(res, left, right);
    return res;
}

int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    build(1, 1, n);
    int p; scanf("%d", &p);
    while(p--) {
        int op, x, y;
        scanf("%d%d%d", &op, &x, &y);
        if(op == 0) modify(1, x, y);
        else {
            node res = query(1, x, y);
            printf("%d\n", res.tmax);
        }
    }
}

 

posted @ 2020-03-10 16:15  hellcat9  阅读(166)  评论(0编辑  收藏  举报