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

问题:对于一颗线段树,每次询问[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\n",res.maxi);

        }

        else

            update(1,n,aa,bb,1);

    }

    return 0;

}
View Code

你可能感兴趣的:(线段树)