参考:http://www.cnblogs.com/staginner/archive/2012/04/18/2455126.html
题意:找出一个区间内的最大的连续和
思路:线段树中维护三个数组,一个是这个区间内的最大连续和,一个是从左往右的最大连续和,一个是从右往左的最大连续和。
错误:一开始想当然的认为,左儿子返回的就是从左往右,右儿子应该返回从右往左。后来发现想错了。返回的左右应当根据父节点的要求来定。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=50005;
int maxv[maxn*4];
int lv[maxn*4];
int rv[maxn*4];
int A[maxn];
void build(int o,int L,int R)
{
if(L==R){
rv[o]=lv[o]=maxv[o]=A[L]-A[L-1];
return ;
} else {
int lc=o*2;
int rc=o*2+1;
int M=L+(R-L)/2;
build(lc,L,M);
build(rc,M+1,R);
maxv[o]=max(maxv[lc],maxv[rc]);
maxv[o]=max(maxv[o],rv[lc]+lv[rc]);
lv[o]=max(lv[lc],A[M]-A[L-1]+lv[rc]);
rv[o]=max(rv[rc],A[R]-A[M]+rv[lc]);
}
}
int ql,qr;
int ans;
int query(int o,int L,int R,int flag)
{
if(ql<=L&&qr>=R){
ans=max(ans,maxv[o]);
return flag==-1?lv[o]:rv[o];
} else {
int M=L+(R-L)/2;
if(M>=qr)
return query(o*2,L,M,-1);
else if(M<ql)
return query(o*2+1,M+1,R,1);
else{
int ln,rn;
ln=query(o*2,L,M,1);
rn=query(o*2+1,M+1,R,-1);
ans=max(ans,ln+rn);
if(flag==-1)
return max(lv[o*2],A[M]-A[L-1]+rn);
else
return max(rv[o*2+1],A[R]-A[M]+ln);
}
}
}
int main()
{
//freopen("data.txt","r",stdin);
int n;
scanf("%d",&n);
A[0]=0;
for(int i=1;i<=n;++i){
scanf("%d",&A[i]);
A[i]=A[i-1]+A[i];
}
build(1,1,n);
int M;
scanf("%d",&M);
for(int i=0;i<M;++i){
int a,b;
scanf("%d%d",&a,&b);
ql=a;
qr=b;
ans=A[b]-A[a-1];
query(1,1,n,1);
printf("%d\n",ans);
}
return 0;
}