• 线段树之区间最大连续和问题


    问题:对于一颗线段树,每次询问[L,R],求此区间中任意一段连续序列,此连续序列和最大。

    解法:每个节点维护4个值:

    max:此区间内的最大连续和

    sum:该节点以下的节点值得总和

    lmax:此区间的从左端开始的最大连续和

    rmax:此区间的从右端开始的最大连续和

     

    合并区间时,该区间的最大连续和为:max(左子节点的最大连续和,右子节点的最大连续和,左子节点的最大右连续和+右子节点的最大左连续和)

    查询时返回一个整节点。因为每次要查询左子节点和右子节点,并且要比较它们的右连续最大和和左连续最大和,所以需要返回整个节点以便求值。

     

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    #define N 200007
    
    struct node
    {
        int maxi,lmaxi,rmaxi,sum;
    }tree[4*N];
    
    void pushup(int rt)
    {
        tree[rt].sum = tree[2*rt].sum + tree[2*rt+1].sum;
        tree[rt].maxi = max(tree[2*rt].maxi,max(tree[2*rt+1].maxi,tree[2*rt].rmaxi+tree[2*rt+1].lmaxi));
        tree[rt].lmaxi = max(tree[2*rt].lmaxi,tree[2*rt].sum + tree[2*rt+1].lmaxi);
        tree[rt].rmaxi = max(tree[2*rt+1].rmaxi,tree[2*rt+1].sum + tree[2*rt].rmaxi);
    }
    
    void build(int l,int r,int rt)
    {
        if(l == r)
        {
            scanf("%d",&tree[rt].sum);
            tree[rt].maxi = tree[rt].lmaxi = tree[rt].rmaxi = tree[rt].sum;
            return;
        }
        int mid = (l+r)/2;
        build(l,mid,2*rt);
        build(mid+1,r,2*rt+1);
        pushup(rt);
    }
    
    void update(int l,int r,int pos,int val,int rt)
    {
        if(l == r)
        {
            tree[rt].maxi = tree[rt].lmaxi = tree[rt].rmaxi = tree[rt].sum = val;
            return;
        }
        int mid = (l+r)/2;
        if(pos <= mid)
            update(l,mid,pos,val,2*rt);
        else
            update(mid+1,r,pos,val,2*rt+1);
        pushup(rt);
    }
    
    node query(int l,int r,int aa,int bb,int rt)
    {
        if(aa <= l && bb >= r)
            return tree[rt];
        int mid = (l+r)/2;
        node ka,kb,res;
        int flag1 = 0;
        int flag2 = 0;
        if(aa <= mid)
        {
            ka = query(l,mid,aa,bb,2*rt);
            flag1 = 1;
        }
        if(bb > mid)
        {
            kb = query(mid+1,r,aa,bb,2*rt+1);
            flag2 = 1;
        }
        if(flag1 && flag2)
        {
            res.sum = ka.sum + kb.sum;
            res.lmaxi = max(ka.lmaxi,ka.sum+kb.lmaxi);
            res.rmaxi = max(kb.rmaxi,kb.sum+ka.rmaxi);
            res.maxi = max(ka.rmaxi+kb.lmaxi,max(ka.maxi,kb.maxi));
        }
        else
        {
            if(flag1)  //left
                res = ka;
            else
                res = kb;
        }
        return res;
    }
    
    int main()
    {
        int n,m,op,aa,bb;
        scanf("%d%d",&n,&m);
        build(1,n,1);
        while(m--)
        {
            scanf("%d%d%d",&op,&aa,&bb);
            if(!op)
            {
                node res = query(1,n,aa,bb,1);
                printf("%d
    ",res.maxi);
            }
            else
                update(1,n,aa,bb,1);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Sublime Text 3 Build 3143 可用License
    npm安装cnpm报错
    使用proxy来简单的实现一个观察者
    时间倒计时提醒
    JavaScript设计模式
    异步方法(promise版)出错自调用
    co模块源码学习笔记
    go new() 和 make() 的区别
    广度优先搜索算法
    并发和并行有什么区别?(转)
  • 原文地址:https://www.cnblogs.com/whatbeg/p/3679055.html
Copyright © 2020-2023  润新知