题目描述
给你一个序列A[1],A[2],...,A[n].(|A[i]| <= 15007, 1 <= N <= 50,000).
M(1 <= M <= 500,000) 次询问,每次询问 Query(x, y) = Max{A[i] + A[i+1] +...+ A[j]; x <= i <= j <= y}.
输入
第一行输入一个数N。
第二行输入N个数A[1],A[2],...,A[n].
第三行输入一个数M
以下M行,每行输入x , y.
输出
M行,每行输出查询的答案。
样例输入 Copy
3
-1 2 3
1
1 2
样例输出 Copy
2
提示
题目大意:求区间最大连续子段和。
解题思路:线段树需要维护的有四个值,sum,maxSum, lsum, rsum。 sum是区间和,maxSum是区间最大连续子段和,lsum是区间最大前缀和,rsum是区间最大后缀和。
sum的维护很常规,
lsum:有两种情况:
1.该区间内的lsum是ta左儿子的lsum
2.该区间内的lsum是左儿子的sum+右儿子的lsum
同理,rsum:有两种情况:
1.该区间内的rsum是ta右儿子的rsum
2.该区间内的rsum是右儿子的sum+左儿子的rsum
而maxSum有三种情况:
1.该区间内的maxSum是左儿子的maxSum
2.该区间内的maxSum是右儿子的maxSum
该区间内的maxSum是左儿子的rsum+右儿子的lsum
以下为题解
#include<bits/stdc++.h>
#define MAXN 500005
#define lson num<1,s,mid
#define rson num<<1|1,mid+1,e
using namespace std;
int tree[MAXN<<2];
int lef[MAXN<<2];
int rig[MAXN<<2];
int X[MAXN]={0};
int n,cnt;
inline void pushup(int num,int s,int e){
int mid=(s+e)>>1;
lef[num]=max(lef[num<<1],X[mid]-X[s-1]+lef[num<<1|1]);
rig[num]=max(rig[num<<1|1],X[e]-X[mid]+rig[num<<1]);
tree[num]=max(lef[num<<1|1]+rig[num<<1],max(tree[num<<1],tree[num<<1|1]));
}void build(int num,int s,int e){
if(s==e){
scanf("%d",&tree[num]);
lef[num]=rig[num]=tree[num];
X[cnt]=X[cnt-1]+tree[num];
cnt++;
return;
}
int mid=(s+e)>>1;
build(num<<1,s,mid);
build(num<<1|1,mid+1,e);
pushup(num,s,e);
}int query(int num,int s,int e,int l,int r,int flag,int &ans){
int mid=(s+e)>>1;
if(s>=l&&e<=r){
ans=max(ans,tree[num]);
return flag == -1 ? lef[num] : rig[num];
}if(mid>=r){
return query(num<<1,s,mid,l,r,-1,ans);
}else if(mid<l){
return query(num<<1|1,mid+1,e,l,r,1,ans);
}else{
int ln,rn;
ln=query(num<<1,s,mid,l,r,1,ans);
rn=query(num<<1|1,mid+1,e,l,r,-1,ans);
ans=max(ans,ln+rn);
if(flag==-1) return max(lef[num<<1],X[mid]-X[s-1]+rn);
else return max(rig[num<<1|1],X[e]-X[mid]+ln);
}
}int main(){
while(scanf("%d",&n)!=EOF){
cnt=1;
X[0]=0;
build(1,1,n);
int m;
scanf("%d",&m);
while(m--){
int aa,bb;
scanf("%d%d",&aa,&bb);
int ans=X[aa]-X[aa-1];
query(1,1,n,aa,bb,-1,ans);
printf("%d\n",ans);
}
}
}
最后别忘了三怜!