acwing245. 你能回答这些问题吗(线段树维护组大连续子段和)

题意

在这里插入图片描述

思路

  1. 单点修改比较好维护,但是区间连续子段和就比较难维护了,我们需要在结构提供维护一些间接条件,在这些间接条件的帮助下我们才能维护出最大连续字段和,我们需要在结构体中维护的条件如下 :
    1. 当前区间最大连续子段和:mx
    2. 当前区间的和:sum
    3. 当前区间的前缀最大值: lmx
    4. 当前区间的后缀最大值:rmx
  2. 维护关系如下图。

在这里插入图片描述
3. 注意区间最大连续子段和 mx 的产生有三种情况:

  1. 最大子段和只在左子区间中产生:l.mx
  2. 最大子段和只在有子区间中产生:r.mx
  3. 最大子段和横跨两个子区间 l,r:l.rmx + r.lmx

代码

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

#define ls (k << 1)
#define rs (k << 1 | 1)

const int N = 500005;
int n, m, a[N];
struct Tree
{
    int l, r;
    int sum, lmx, rmx, mx;
} tr[N * 4];

void push_up(Tree & u, Tree l, Tree r)
{
    u.sum = l.sum + r.sum;
    u.lmx = max(l.lmx, l.sum + r.lmx);
    u.rmx = max(r.rmx, r.sum + l.rmx);
    u.mx = max(max(l.mx, r.mx), l.rmx + r.lmx);
}

void build(int k, int l, int r)
{
    tr[k] = { l, r };
    if (l == r)
    {
        tr[k] = { l, r, a[l], a[l], a[l], a[l] };
        return;
    }

    int md = (l + r) >> 1;
    build(ls, l, md);
    build(rs, md + 1, r);
    push_up(tr[k], tr[ls], tr[rs]);
}

void update(int k, int x, int v)
{
    if (tr[k].l == x && tr[k].r == x) 
    {
        tr[k] = { x, x, v, v, v, v };
        return;
    }

    int md = (tr[k].l + tr[k].r) >> 1;
    if (x <= md) update(ls, x, v);
    else update(rs, x, v);
    push_up(tr[k], tr[ls], tr[rs]);
}

Tree query(int k, int l, int r)
{
    if (tr[k].l >= l && tr[k].r <= r) return tr[k];

    int md = (tr[k].l + tr[k].r) >> 1;

    if (r <= md) return query(ls, l, r);
    else if (l > md) return query(rs, l, r);
    else
    {
        Tree t;
        push_up(t, query(ls, l, r), query(rs, l, r));
        return t;
    }
}

int main()
{
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; i ++) scanf("%d", &a[i]);
    build(1, 1, n);
    int op, x, y;
    while (m --)
    {
        scanf("%d %d %d", &op, &x, &y);
        if (op == 1)
        {
            if (x > y) swap(x, y);
            printf("%d\n", query(1, x, y).mx);
        }
        else
        {
            update(1, x, y);
        }
    }


    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值