Can you answer these queries III 线段树求区间最大字段和

题目:

You are given a sequence A of N (N <= 50000) integers between -10000 and 10000. On this sequence you have to apply M (M <= 50000) operations: 
modify the i-th element in the sequence or for given x y print max{Ai + Ai+1 + .. + Aj | x<=i<=j<=y }.

输入:

The first line of input contains an integer N. The following line contains N integers, representing the sequence A1..AN. 
The third line contains an integer M. The next M lines contain the operations in following form:
0 x y: modify Ax into y (|y|<=10000).
1 x y: print max{Ai + Ai+1 + .. + Aj | x<=i<=j<=y }.

输出:

For each query, print an integer as the problem required.

样例输入:

4
1 2 3 4
4
1 1 3
0 3 -3
1 2 4
1 3 3

样例输出:

6
4
-3

题意:给出两个操作,一个是换数,一个是求区间最大子段和。

要求区间最大子段和我们需要用到四个数据。

tree[x].sum,表示区间x 的每个点的权值之和
tree[x].maxx    表示区间x 的最大子段和
tree[x].lmax ,表示区间x 的含点tree[x].l的最大子段和
tree[x].rmax,表示区间x xx的含点tree[x].r 的最大子段和

很明显,tree[x].sum=tree[x<<1].sum+tree[rt<<1|1].sum;

tree[x].lmax有多种可能:

1.完全位于左儿子中   2.占据了全部的左儿子,并有一部分在右儿子中,并且这一部分在右儿子的最左边

那么tree[x].lmax=max(tree[rt<<1].lmax,tree[rt<<1].sum+tree[rt<<1|1].lmax);

同理可得

tree[x].rmax=max(tree[rt<<1|1].rmax,tree[rt<<1|1].sum+tree[rt<<1].rmax);

最后还剩下一个tree[x].maxx有三种可能:

  1. 完全是右儿子的最大子段和
  2. 完全是左儿子的最大子段和
  3. 既有一部分在左儿子中,又有一部分在右儿子 

所以tree[x].maxx=max(tree[rt<<1].rmax+tree[rt<<1|1].lmax,max(tree[rt<<1].maxx,tree[rt<<1|1].maxx)); (借鉴于https://blog.csdn.net/SSL_ZYC/article/details/81951129

AC代码:

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn=50005;
int a[maxn];
struct tree
{
    int lmax,rmax,maxx,sum;
}node[maxn<<2];
void pushup(int rt)
{
    tree L=node[rt<<1],R=node[rt<<1|1];
    node[rt].sum=L.sum+R.sum;
    node[rt].lmax=max(L.lmax,L.sum+R.lmax);
    node[rt].rmax=max(R.rmax,R.sum+L.rmax);
    node[rt].maxx=max(L.rmax+R.lmax,max(L.maxx,R.maxx));
}
void build(int l,int r,int rt)
{
    if(l==r)
    {
        node[rt].lmax=node[rt].maxx=node[rt].rmax=node[rt].sum=a[l];
        return ;
    }
    int m=(l+r)>>1;
    build(l,m,rt<<1);
    build(m+1,r,rt<<1|1);
    pushup(rt);
}
void update(int L,int c,int l,int r,int rt)
{
    if(l==r)
    {
        node[rt].lmax=node[rt].maxx=node[rt].rmax=node[rt].sum=c;
        return ;
    }
    int m=(l+r)>>1;
    if(L<=m) update(L,c,l,m,rt<<1);
    else update(L,c,m+1,r,rt<<1|1);
    pushup(rt);
}
tree QuerY(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R)
        return node[rt];
    int m=(l+r)>>1;
    if(R<=m) return QuerY(L,R,l,m,rt<<1);
    if(L>m)  return QuerY(L,R,m+1,r,rt<<1|1);
    tree LL=QuerY(L,m,l,m,rt<<1),RR=QuerY(m+1,R,m+1,r,rt<<1|1),res;
    res.sum=LL.sum+RR.sum;
    res.lmax=max(LL.lmax,LL.sum+RR.lmax);
    res.rmax=max(RR.rmax,RR.sum+LL.rmax);
    res.maxx=max(RR.lmax+LL.rmax,max(LL.maxx,RR.maxx));
    return res;

}
int main()
{
    int n,m;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    build(1,n,1);
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        if(a==1)
        {
            tree s=QuerY(b,c,1,n,1);
            printf("%d\n",s.maxx);
        }
        else
        {
            update(b,c,1,n,1);
        }
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值