Acwing 245. 你能回答这些问题吗

解题思路: 一开始表示线段树的结构体中只有l,r,要维护当前区间的最大子段和,那么向其中加入表示最大子段和的变量tmax,然后我们考虑如何从下往上去更新tmax,发现以我们现在的变量无法对其进行更新,那么来看一下当前区间的最大子段和等于什么,其应该等于左子树的最大子段和,右子树的最大子段和,还有一种可能是最大子段和横跨左右两个区间,这种情况下最大子段和就等于左区间的最大后缀和+右区间的最大前缀和,这样以来tmax可以得到更新了,但是又多出来2个变量,最大前缀和lmax,最大后缀和rmax,这两个变量怎么更新来?,当前区间的最大前缀和可能来源于2总情况,一种是左区间的最大前缀和,一种是左区间的和+右区间的最大前缀和,当前区间的最大后缀和同理=max(右区间的最大后缀和,右区间的和+左区间的最大后缀和),然后又出现了一个变量区间和。。。。,幸运的是这个属性比较好维护,所以综上所述,我们除了l,r之外还需要维护4个变量。

直接上代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
const int N=5e5+10;
using namespace std;
int a[N];
struct node{
    int l,r;
    int tmax;
    int lmax,rmax;
    int sum;
}tr[N<<2];
void pushup(node &u,node &l,node &r)
{
    u.lmax=max(l.lmax,l.sum+r.lmax);
    u.rmax=max(r.rmax,l.rmax+r.sum);
    u.sum=l.sum+r.sum;
    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 rt,int l,int r)
{
    if(l==r)
    {
        tr[rt]={l,l,a[l],a[l],a[l],a[l]};
        return ;
    }
    else
    {
        tr[rt].l=l;
        tr[rt].r=r;
        int mid=l+r>>1;
        build(rt<<1,l,mid);
        build(rt<<1|1,mid+1,r);
        pushup(rt);
    }
}
void  modify(int rt,int x,int y)
{
    if(tr[rt].l==x&&tr[rt].r==x)
    {
        tr[rt]={x,x,y,y,y,y};
        return ;
    }
    else
    {
        int mid=tr[rt].l+tr[rt].r>>1;
        if(x<=mid)
        modify(rt<<1,x,y);
        if(x>mid)
        modify(rt<<1|1,x,y);
        pushup(rt);
    }
}
node query(int rt,int l,int r)
{
    if(tr[rt].l>=l&&tr[rt].r<=r)
        return tr[rt];
    else
    {
        int mid=tr[rt].l+tr[rt].r>>1;
        if(r<=mid)
        return query(rt<<1,l,r);
        else if(l>mid)
        return query(rt<<1|1,l,r);
        else//如果要查询的区间横跨左右两个区间,那么将左右区间的答案算出后再合并成一个新的节点就好了
        {
            node left=query(rt<<1,l,r);
            node right=query(rt<<1|1,l,r);
            node res;
            pushup(res,left,right);
            return res;
        }
    }
}
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    cin>>a[i];
    build(1,1,n);
    for(int i=1;i<=m;i++)
    {
        int op,x,y;
        cin>>op>>x>>y;
        if(op==1)
        {
            if(x>y)
            swap(x,y);
            cout<<query(1,x,y).tmax<<endl;
        }
        else
        modify(1,x,y);
    }
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值