线段树维护最大字段和详解

简述

  线段树可以维护区间信息,区间和,区间最大最小或区间gcd等,通过区间的维护我们还可以在O()的时间求出一个区间的最大子段和。

做法

  首先我们线段树维护的节点变成结构体维护四个值,s为区间的和,ls为从左端点开始的最大字段和,rs为右端点开始的最大字段和,ms为区间的最大字段和。

struct node{
    ll ls,rs,ms,s;
}a[maxn<<2];

如何向上更新

  我们发现对于一个节点的ms,若已经知道了它的左右子树的信息。

  它的ms一定等于左子树的ms或右子树的ms或两个都取一点。

  它的ls要么取左子树的ls,要么取左子树的全部加右子树的ls。 

  它的rs要么取右子树的rs,要么取右子树的全部加左子树的rs。

  它的s就是标准的线段树两子数相加。

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

单点更新

  操作和标准线段树类似就不多说了。

void update(int pos,ll val,int l,int r,int rt){
    //pos位置加val 
    if(l==r){
        ll tmp=a[rt].ms+val;
        a[rt].ls=a[rt].rs=a[rt].s=a[rt].ms=tmp;
        return;
    }
    int m=l+r>>1;
    if(pos<=m)
        update(pos,val,l,m,rt<<1);
    else
        update(pos,val,m+1,r,rt<<1|1);
    pushup(rt);
}

区间查询 (查询区间最大字段和)

node query(int L,int R,int l,int r,int rt){
    //返回代表查询区间信息的节点 
    if(L<=l&&r<=R){
        return a[rt];
    }
    int m=l+r>>1;
    node f1,f2,ans;
    if(R<=m)
        ans=query(L,R,l,m,rt<<1);
    if(L>m)
        ans=query(L,R,m+1,r,rt<<1|1);
    if(L<=m&&R>m){
        f1=query(L,R,l,m,rt<<1);
        f2=query(L,R,m+1,r,rt<<1|1);
        ans.s=f1.s+f2.s;
        ans.ls=max(f1.ls,f1.s+f2.ls);
        ans.rs=max(f2.rs,f2.s+f1.rs);
        ans.ms=max(max(f1.ms,f2.ms),f1.rs+f2.ls);
    }
    return ans;
}

时间复杂度

  对于单点更新和区间查询,时间复杂度都是logn,递归过程和标志线段树是类似的。

模板

#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=;
typedef long long ll;

ll A[maxn];
struct node{
    ll ls,rs,ms,s;
}a[maxn<<2];

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

void build(int l,int r,int rt){
    if(l==r){
        a[rt].ls=a[rt].rs=a[rt].ms=a[rt].s=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 pos,ll val,int l,int r,int rt){
    //pos位置加val 
    if(l==r){
        ll tmp=a[rt].ms+val;
        a[rt].ls=a[rt].rs=a[rt].s=a[rt].ms=tmp;
        return;
    }
    int m=l+r>>1;
    if(pos<=m)
        update(pos,val,l,m,rt<<1);
    else
        update(pos,val,m+1,r,rt<<1|1);
    pushup(rt);
}

node query(int L,int R,int l,int r,int rt){
    //返回代表查询区间信息的节点 
    if(L<=l&&r<=R){
        return a[rt];
    }
    int m=l+r>>1;
    node f1,f2,ans;
    if(R<=m)
        ans=query(L,R,l,m,rt<<1);
    if(L>m)
        ans=query(L,R,m+1,r,rt<<1|1);
    if(L<=m&&R>m){
        f1=query(L,R,l,m,rt<<1);
        f2=query(L,R,m+1,r,rt<<1|1);
        ans.s=f1.s+f2.s;
        ans.ls=max(f1.ls,f1.s+f2.ls);
        ans.rs=max(f2.rs,f2.s+f1.rs);
        ans.ms=max(max(f1.ms,f2.ms),f1.rs+f2.ls);
    }
    return ans;
}

int main()
{
    
    return 0;
}
View Code

 

  

 

posted @ 2020-03-26 21:27  艾尔夏尔-Layton  阅读(718)  评论(0编辑  收藏  举报