SPOJ 1043 Can you answer these queries I(GSS1 线段树)
http://www.spoj.pl/problems/GSS1/
题意:给一个序列,求区间的最大连续子序列和。
思路:维护三个值区间的最大连续和,左端连续的最大和。右端连续的最大连续和。
查询的时候先看左右两个区间的最大连续和,再看两区间交界处的最大连续和。(参考:http://blog.csdn.net/acm_cxlove/article/details/7982444)

#include<stdio.h> #include<string.h> #include<iostream> using namespace std; const int maxn = 50005; int sum[maxn],bs[maxn]; struct nd{ int l,r,lx,rx,mx; int all(){return sum[r]-sum[l-1];}//整个区间和 }as[maxn*4]; void pushUp(int rt) { //max(左孩子的左端最大连续和,左区间总和+右区间的左端最大连续和)==>构成当前区间的左端最大连续和 as[rt].lx = max(as[rt<<1].lx,as[rt<<1].all()+as[rt<<1|1].lx); //max(右孩子 的右端最大连续和,右区间的总和+左区间的右端最大连续和)==>构成当前区间的右端最大连续和 as[rt].rx = max(as[rt<<1|1].rx,as[rt<<1|1].all()+as[rt<<1].rx); //max(左右孩子的最大连续区间和,左孩子的右端最大连续和+右孩子的左端最大连续和)==>构成当前区间的最大连续和 as[rt].mx = max(max(as[rt<<1].mx,as[rt<<1|1].mx),as[rt<<1].rx+as[rt<<1|1].lx); } void build(int rt,int l,int r) { int md = (l + r) >> 1; as[rt].l = l; as[rt].r = r; if(l==r){ as[rt].lx = as[rt].rx = as[rt].mx = bs[l]; return; } build(rt<<1,l,md); build(rt<<1|1,md+1,r); pushUp(rt); } //注意:区间[l,r],l一定是所查询左端最大连续和中的值之一 int queryL(int rt,int l,int r) { int md = (as[rt].l+as[rt].r) >> 1; if(as[rt].l==l && r==as[rt].r) return as[rt].lx; if(r<=md)return queryL(rt<<1,l,r); if(l>md) return queryL(rt<<1|1,l,r); //max(左孩子的左端最大连续和,max(左区间的总和,左区间的总和+右区间的左端最大连续和)) return max(queryL(rt<<1,l,md),max(sum[md]-sum[l-1],sum[md]-sum[l-1]+queryL(rt<<1|1,md+1,r))); } //注意:区间[l,r],r一定是所查询右端最大连续和中的值之一 int queryR(int rt,int l,int r) { int md = (as[rt].l + as[rt].r) >> 1; if(as[rt].l==l && r==as[rt].r) return as[rt].rx; if(r<=md)return queryR(rt<<1,l,r); if(l>md) return queryR(rt<<1|1,l,r); //max(右孩子的右端最大连续和,max(右区间的总和,右区间的总和+左区间的右端最大连续和)) return max(queryR(rt<<1|1,md+1,r),max(sum[r]-sum[md],sum[r]-sum[md]+queryR(rt<<1,l,md))); } int query(int rt,int l,int r) { int md = (as[rt].l + as[rt].r) >> 1; if(as[rt].l==l&&as[rt].r==r) return as[rt].mx; if(r<=md)return query(rt<<1,l,r); if(l>md) return query(rt<<1|1,l,r); //max(左右区间的最大连续和,左区间的右端最大连续和+右区间的左端最大连续和) else return max(max(query(rt<<1,l,md),query(rt<<1|1,md+1,r)),queryR(rt<<1,l,md)+queryL(rt<<1|1,md+1,r)); } int main() { int n,q,i,l,r; while(scanf("%d",&n)==1){ for(i = 1; i <= n; ++ i){ scanf("%d",bs+i); sum[i] = sum[i-1] + bs[i]; } build(1,1,n); scanf("%d",&q); while(q--){ scanf("%d %d",&l,&r); printf("%d\n",query(1,l,r)); } } return 0; } /* 10 1 2 3 4 5 6 7 8 9 10 10 */