线段树维护区间最大连续和

在我的理解中,线段树就是线段组成的树,越靠近根部的层,线段的长度越长,一个结构体(树的每一个点的左边界,右边界以及要维护的值)和三个函数(build——拆的过程),update(更新的过程,更新的时候要先二分找到最底层的区间,然后需要向上将所有的区间都更新了),query(寻找的过程)。

http://acm.uestc.edu.cn/#/problem/show/844
这个题目的意思就是给一个区间,然后求指定子区间的最大的连续和,在这个过程中还可以不断更新数据。
这个要理清楚结构体里要存的东西,即要维护的东西,是四个值,定义为ssum、sum_、suml,sumr。

#include<iostream>
using namespace std;

int power[100005];
typedef struct Tree
{
    int left,right;
    int ssum;//此区间内最大连续和 
    int sum_;//该节点以下的节点值得总和 
    int suml;//此区间得左端开始的最大连续和 
    int sumr;//此区间得右端开始的最大连续和 
};

Tree tree[100005*4]; 
int num=0;

void build(int root,int left,int right)
{
    tree[root].left=left;
    tree[root].right=right;
    if(left==right)
    {
        num=root;
        tree[root].ssum=power[left];
        tree[root].suml=power[left];
        tree[root].sum_=power[left];
        tree[root].sumr=power[left];
    }
    else
    {
        int mid=(left+right)/2;
        build(root*2,left,mid);
        build(root*2+1,mid+1,right);
        tree[root].sum_=tree[root*2].sum_+tree[root*2+1].sum_;
        //sum_代表的是这个区间的和,那么只要把左区间的和以及右区间的和给加起来就好
        tree[root].ssum=max(max(tree[root*2].ssum,tree[root*2+1].ssum),(tree[root*2].sumr+tree[root*2+1].suml));
        //这个是比较关键的,已知一个区间的左右区间的最大连续和怎么合并,要么就是左区间的最大连续和,要么就是右区间的最大连续和,要么就是左区间的最大右起连续和+右区间的最大左起连续和
        tree[root].suml=max(tree[root*2].suml,tree[2*root].sum_+tree[2*root+1].suml);
        //该区间从左边起的最大连续和,要么就是左子区间的最大左起连续和要么就是左子区间的和+右子区间的最大左起连续和,这也是我们维护一个区间的和的原因。
        tree[root].sumr=max(tree[root*2+1].sumr,tree[2*root].sumr+tree[2*root+1].sum_);
    }
}

Tree query_sum(int root,int left,int right)
{
    if(tree[root].left==left&&tree[root].right==right)
        return tree[root];
    else
    {
        int mid=(tree[root].left+tree[root].right)/2;
        if(right<=mid)
            return query_sum(2*root,left,right);
        if(left>mid)
            return query_sum(2*root+1,left,right);

        Tree k1,k2,temp;    
        k1=query_sum(2*root,left,mid);
        k2=query_sum(2*root+1,mid+1,right);

        temp.sum_=k1.sum_+k2.sum_;
        temp.ssum=max(max(k1.ssum,k2.ssum),k1.sumr+k2.suml);
        temp.suml=max(k1.suml,k1.sum_+k2.suml);
        temp.sumr=max(k2.sumr,k1.sumr+k2.sum_);
        return temp;

    }
}

void update(int root,int pos,int value)
//更新函数就是先不断二分找到位置,然后要像建树一样合并区间
{
    if(tree[root].left==tree[root].right)
    {
        tree[root].ssum=value;
        tree[root].suml=value;
        tree[root].sum_=value;
        tree[root].sumr=value;  
    }
    else
    {
        int mid=(tree[root].left+tree[root].right)/2;
        if(pos<=mid)
            update(2*root,pos,value);
        else
            update(2*root+1,pos,value);
        tree[root].sum_=tree[root*2].sum_+tree[root*2+1].sum_;
        tree[root].ssum=max(max(tree[root*2].ssum,tree[root*2+1].ssum),(tree[root*2].sumr+tree[root*2+1].suml));
        tree[root].suml=max(tree[root*2].suml,tree[2*root].sum_+tree[2*root+1].suml);
        tree[root].sumr=max(tree[root*2+1].sumr,tree[2*root].sumr+tree[2*root+1].sum_);     
    }   
} 

int main()
{
    int n,m;
    scanf("%d %d",&n,&m);
    int i;
    for(i=1;i<=n;i++)
        scanf("%d",&power[i]);
    build(1,1,n);
    for(i=0;i<m;i++)
    {
        int type,loperate,roperate;
        scanf("%d%d%d",&type,&loperate,&roperate);
        if(type)
        {
            update(1,loperate,roperate);
        }
        else
        {
            Tree temp=query_sum(1,loperate,roperate);
            printf("%d\n",temp.ssum);
        }
    }

    return 0;
}

https://vjudge.net/contest/208944#problem/J

#include<iostream>
using namespace std;

long long power[100005];
typedef struct Tree
{
    int left,right;
    long long ssum;//此区间内最大连续和 
    long long sum_;//该节点以下的节点值得总和 
    long long suml;//此区间得左端开始的最大连续和 
    long long sumr;//此区间得右端开始的最大连续和 
};

Tree tree[100005*4]; 
int num=0;

void build(int root,int left,int right)
{
    tree[root].left=left;
    tree[root].right=right;
    if(left==right)
    {
        num=root;
        tree[root].ssum=power[left];
        tree[root].suml=power[left];
        tree[root].sum_=power[left];
        tree[root].sumr=power[left];
    }
    else
    {
        int mid=(left+right)/2;
        build(root*2,left,mid);
        build(root*2+1,mid+1,right);
        tree[root].sum_=tree[root*2].sum_+tree[root*2+1].sum_;
        tree[root].ssum=max(max(tree[root*2].ssum,tree[root*2+1].ssum),(tree[root*2].sumr+tree[root*2+1].suml));
        tree[root].suml=max(tree[root*2].suml,tree[2*root].sum_+tree[2*root+1].suml);
        tree[root].sumr=max(tree[root*2+1].sumr,tree[2*root].sumr+tree[2*root+1].sum_);
    }
}

Tree query_sum(int root,int left,int right)
{
    if(tree[root].left>=left&&tree[root].right<=right)
        return tree[root];
    else
    {
        int mid=(tree[root].left+tree[root].right)/2;
        if(right<=mid)
            return query_sum(2*root,left,right);
        if(left>mid)
            return query_sum(2*root+1,left,right);

        Tree k1,k2,temp;    
        k1=query_sum(2*root,left,mid);
        k2=query_sum(2*root+1,mid+1,right);

        temp.sum_=k1.sum_+k2.sum_;
        temp.ssum=max(max(k1.ssum,k2.ssum),k1.sumr+k2.suml);
        temp.suml=max(k1.suml,k1.sum_+k2.suml);
        temp.sumr=max(k2.sumr,k1.sumr+k2.sum_);
        return temp;

    }
}

void update(int root,int pos,int value)
{
    if(tree[root].left==tree[root].right)
    {
        tree[root].ssum=value;
        tree[root].suml=value;
        tree[root].sum_=value;
        tree[root].sumr=value;  
    }
    else
    {
        int mid=(tree[root].left+tree[root].right)/2;
        if(pos<=mid)
        update(2*root,pos,value);
        else
        update(2*root+1,pos,value);
        tree[root].sum_=tree[root*2].sum_+tree[root*2+1].sum_;
        tree[root].ssum=max(max(tree[root*2].ssum,tree[root*2+1].ssum),(tree[root*2].sumr+tree[root*2+1].suml));
        tree[root].suml=max(tree[root*2].suml,tree[2*root].sum_+tree[2*root+1].suml);
        tree[root].sumr=max(tree[root*2+1].sumr,tree[2*root].sumr+tree[2*root+1].sum_);     
    }   
} 

int main()
{
    int n;
    scanf("%d",&n);
    int i;
    for(i=1;i<=n;i++)
        scanf("%lld",&power[i]);
    build(1,1,n);
    //for(i=1;i<=num;i++)
    //  cout<<tree[i].left<<" "<<tree[i].right<<" "<<tree[i].ssum<<" "<<tree[i].sum_<<" "<<tree[i].suml<<" "<<tree[i].sumr<<endl;
    for(i=0;i<n;i++)
    {
        long long x;
        scanf("%lld",&x);
        update(1,x,-10000000000000000);
        Tree temp=query_sum(1,1,n);
        if(temp.ssum>=0)
            printf("%lld\n",temp.ssum);
        else
            printf("0\n");
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值