Fork me on GitHub

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

问题:对于一颗线段树,每次询问[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
posted @ 2014-04-21 19:16  whatbeg  阅读(1599)  评论(0编辑  收藏  举报