求区间最大连续子段和.new(线段树)

这个故事是这样的:
在n年前,憨憨博主在参加省队集训的时候,第一次接触到了这个问题:区间最大连续子段和,
于是博主就开始一阵恶补,get了这种新技能

然而在夏季的一个宁静的午后,博主的CSDN突然接到消息通知,发现好心的大佬给我指出了我写的代码的不足,憨憨博主非常惭愧。。。

前端时间都在忙着大学的各种事项,没有抽出时间来修正这个错误
十一假期留校,突然想起来了我好像还有个大坑没有填,于是就上网查看了一下
发现竟然还有小伙伴在解决这一问题的时候引用的是我的blog。。。误人子弟啊~~
废话不多说,赶紧献上崭新的解题姿态~


首先,这个“区间最大子段和”是个什么玩意呢

题目给出 n n n个数, q q q次操作,每次改一个值,或者询问区间 [ L , R ] [L,R] [L,R]内最大的连续子段和

哎呦,感觉很像线段树的题目哦
毕竟我们是会用线段树求区间最大(小)值的
但是现在题目要求的是最大子段和,问题的难度就上升了一个数量级

线段树需要维护的是:
[ x , y ] [x,y] [x,y]内的最大子段和 m s ms ms
[ x , y ] [x,y] [x,y]的区间和 s s s
[ x , y ] [x,y] [x,y]内的紧靠左端点的最大子段和 l s ls ls
[ x , y ] [x,y] [x,y]内的紧靠右端点的最大子段和 r s rs rs

困难就是, u p d a t e update update a s k ( L , R ) ask(L,R) ask(L,R)询问 [ L , R ] [L,R] [L,R]区间内的最大子段和
那我们一步一步来,从维护说起

s s s的维护很常规,
l s : ls: ls有两种情况:

  1. 该区间内的 l s ls ls是ta左儿子的 l s ls ls
  2. 该区间内的 l s ls ls是左儿子的 s s s+右儿子的 l s ls ls

同理, r s : rs: rs有两种情况:

  1. 该区间内的 r s rs rs是ta右儿子的 r s rs rs
  2. 该区间内的 r s rs rs是右儿子的 s s s+左儿子的 r s rs rs

m s ms ms有三种情况:

  1. 该区间内的 m s ms ms是左儿子的 m s ms ms
  2. 该区间内的 m s ms ms是右儿子的 m s ms ms
  3. 该区间内的 m s ms ms是左儿子的 r s + rs+ rs+右儿子的 l s ls ls

在这里插入图片描述

void pushup(int bh) {
    int lson=bh<<1;
    int rson=bh<<1|1;
    tree[bh].s=tree[lson].s+tree[rson].s;
    tree[bh].ls=max(tree[lson].ls,tree[lson].s+tree[rson].ls);
    tree[bh].rs=max(tree[rson].rs,tree[rson].s+tree[lson].rs);
    tree[bh].ms=max(max(tree[lson].ms,tree[rson].ms),tree[lson].rs+tree[rson].ls);
}

那询问呢~

其实道理是一样哒
[ L , R ] [L,R] [L,R]内的区间最大子段和分以下几种情况:
1.独立的存在于左儿子或右儿子中
2.左儿子的 r s rs rs+右儿子的 l s ls ls
然而如果 [ L , R ] [L,R] [L,R]在线段树中是一个节点(我们单独维护过),那我们直接 r e t u r n return return m s ms ms就好啦

下面给出完整代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define LL long long

using namespace std;

const int M=10000;
struct node{
    LL s,ls,rs,ms;
}tree[M<<2];

void pushup(int bh) {
    int lson=bh<<1;
    int rson=bh<<1|1;
    tree[bh].s=tree[lson].s+tree[rson].s;
    tree[bh].ls=max(tree[lson].ls,tree[lson].s+tree[rson].ls);
    tree[bh].rs=max(tree[rson].rs,tree[rson].s+tree[lson].rs);
    tree[bh].ms=max(max(tree[lson].ms,tree[rson].ms),tree[lson].rs+tree[rson].ls);
}

void build(int L,int R,int bh) {
    if (L==R) {
        scanf("%lld",&tree[bh].s);
        tree[bh].ls=tree[bh].rs=tree[bh].ms=tree[bh].s;
        return;
    }
    int mid=(L+R)>>1;
    build(L,mid,bh<<1);
    build(mid+1,R,bh<<1|1);
    pushup(bh);
}

void update(int x,int z,int L,int R,int bh) {
    if (L==R) {
        tree[bh].ls=tree[bh].rs=tree[bh].ms=tree[bh].s=z;
        return;
    }
    int mid=(L+R)>>1;
    if (x<=mid) update(x,z,L,mid,bh<<1);
    else update(x,z,mid+1,R,bh<<1|1);
    pushup(bh);
}

node askans(int x,int y,int L,int R,int bh) {
    if (x<=L&&y>=R) return tree[bh];   //完全包含
    int mid=(L+R)>>1;
    node f1,f2,T;
    T.s=0;
    if (y<=mid)   //全部都在左儿子
        T=askans(x,y,L,mid,bh<<1);
    if (x>mid)     //全部都在右儿子
        T=askans(x,y,mid+1,R,bh<<1|1);
    if (x<=mid&&y>mid) {     //询问区间被拆成两部分
        f1=askans(x,y,L,mid,bh<<1);
        f2=askans(x,y,mid+1,R,bh<<1|1);
  
        T.s=f1.s+f2.s;
        T.ls=max(f1.ls,f1.s+f2.ls);
        T.rs=max(f2.rs,f2.s+f1.rs);
        T.ms=max(max(f1.ms,f2.ms),f1.rs+f2.ls);
 }
    return T;
}

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    build(1,n,1);
    while (m--) {
        int typ,x,y;
        scanf("%d%d%d",&typ,&x,&y);
        if (typ==1) {
            if (x>y) swap(x,y);
            node ans=askans(x,y,1,n,1);
            printf("%d\n",ans.ms);
        }
        else update(x,y,1,n,1);
    }
    //system("pause");
    return 0;
}

Tip

第一次用VS写代码,有点小费劲
在上传代码的时候,不知道是CSDN的锅还是我的笔记本的锅
在复制粘贴的时候如果代码中出现空行就会导致我的blog内容全部丢失
所以花了好长的时间才完成了排版QwQ

后来发现是浏览器的问题,微软自带的浏览器(Microsoft Edge)对Markdown的兼容性不好,换成Chrome就OK啦

关于VS有自动格式化的问题
缩进排版什么的确实有
但是如果用Edge上传(复制粘贴),所有的排版就会全部乱掉,真的惨啊。。。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值