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

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

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

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

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

#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 阅读(...) 评论(...) 编辑 收藏