线段树连续区间的和

思路:

我们知道pushup我们是根据子区间求解父区间的,然后连续区间和,我们并不确定子区间连续的是那一段,就假如子区间二中最大区间和的区间是(2——3),子区间二中最大的区间和是(5--6)父亲区间是(1--6)那这时候父亲区间连续区间的最大值应该分为三类情况讨论:(1)区间二的最大区间和(2)区间三的最大区间和(3)区间二的最大后缀和加上区间三的最大前缀和的结果,将这三类结果进行比较。所以我们需要在树的结构体中存储,最大区间和,最大前缀和,最大后缀和,然后最大前缀和,最大前缀和的求值,(这里记得最大前缀和是指父亲区间前n个数字的和最大,最大后缀和就是后n个数字的和最大)我们同样用上述例子举例,父亲区间的最大前缀和,我们分为两种情况:(1)区间二的最大前缀和(2)区间二的和+区间三的最大前缀和。后缀和同样两种情况:(1)区间三的最大后缀和(2)区间三的和+区间二的最大后缀和。因此结构体中我们还需要加入区间的和

    u.summ=l.summ+r.summ;
    u.tmax=max(max(l.tmax,r.tmax),l.rmax+r.lmax);
    u.lmax=max(l.lmax,l.summ+r.lmax);
    u.rmax=max(r.rmax,r.summ+l.rmax);

还有就是查询时,看我的代码注释吧,不想写了

代码:

#include<iostream>
using namespace std;
const int N=1e5+10;
int w[N];
struct Node{
    int l,r;
    int summ,tmax,lmax,rmax;
}tr[N*4];
void pushup(Node &u,Node &l,Node &r)
{
    u.summ=l.summ+r.summ;
    u.tmax=max(max(l.tmax,r.tmax),l.rmax+r.lmax);
    u.lmax=max(l.lmax,l.summ+r.lmax);
    u.rmax=max(r.rmax,r.summ+l.rmax);
}
void pushup(int u)
{
    int l=u<<1;
    int r=u<<1|1;
    pushup(tr[u],tr[l],tr[r]);
}
void build(int u,int l,int r)
{
    if(l==r)
    {
        tr[u]={l,r,w[l],w[l],w[l],w[l]};
    }
    else
    {
        tr[u]={l,r};
        int mid=l+r>>1;
        build(u<<1,l,mid);
        build(u<<1|1,mid+1,r);
        pushup(u);
    }
}
int modify(int u,int x,int v)
{
    if(tr[u].l==x&&tr[u].r==x)
    {
        tr[u]={x,x,v,v,v,v};
    }
    else
    {
        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)//整个u里面的都是我们要查找的范围
    return tr[u];
    int mid=tr[u].l+tr[u].r>>1;
    if(r<=mid)return query(u<<1,l,r);//只有前半部分跟我们要查找的有交集
    else if(l>mid)return query(u<<1|1,l,r);//只有后半部分跟我们要查找的有交集
    else//前后部分都跟我们要查找的有交集,但是整个u里面的内容并不都是我们要查找的
    {
        Node left=query(u<<1,l,r);
        Node right=query(u<<1|1,l,r);
        Node res;
        pushup(res,left,right);//因为left和right返回的值不一定是相邻的两个序号的最大连续和
        return res; 
    }
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    scanf("%d",&w[i]);
    build(1,1,n);
    int k,x,y;
    while(m--)
    {
        scanf("%d%d%d",&k,&x,&y);
        if(k==1)
        {
            if(x>y)swap(x,y);
            printf("%d\n",query(1,x,y).tmax);
        }
        else
        {
            modify(1,x,y);
        }
    }
    return 0;
}
//5 3
// 1 2 -3 4 5
//1 2 3
//2 2 -1
//1 3 2

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值