题意:多次查询区间最长连续字段和
/* 用线段树维护区间最长子段和,最长左子段和,最长右子段和。 */ #include<cstdio> #include<iostream> #define N 50010 using namespace std; int a[N],s[N],sum[N*4],lsum[N*4],rsum[N*4],n,m; void push_up(int k,int l,int r){ int mid=l+r>>1; lsum[k]=max(lsum[k*2],s[mid]-s[l-1]+lsum[k*2+1]); rsum[k]=max(rsum[k*2+1],rsum[k*2]+s[r]-s[mid]); sum[k]=max(max(sum[k*2],sum[k*2+1]),rsum[k*2]+lsum[k*2+1]); sum[k]=max(max(sum[k*2],sum[k*2+1]),rsum[k*2]+lsum[k*2+1]); } void build(int l,int r,int k){ int mid=l+r>>1; if(l==r){ sum[k]=lsum[k]=rsum[k]=a[l]; return; } build(l,mid,k*2); build(mid+1,r,k*2+1); push_up(k,l,r); } int query_l(int l,int r,int k,int x,int y){//询问最长左子段和 if(l==x&&r==y)return lsum[k]; int mid=l+r>>1; if(y<=mid) return query_l(l,mid,k*2,x,y); else { return max(lsum[k*2],s[mid]-s[l-1]+query_l(mid+1,r,k*2+1,mid+1,y)); } } int query_r(int l,int r,int k,int x,int y){//询问最长右子段和 if(l==x&&r==y)return rsum[k]; int mid=l+r>>1; if(x>mid) return query_r(mid+1,r,k*2+1,x,y); else { return max(rsum[k*2+1],s[r]-s[mid]+query_r(l,mid,k*2,x,mid)); } } int query(int l,int r,int k,int x,int y){ if(l==x&&r==y) return sum[k]; int mid=l+r>>1; if(y<=mid)return query(l,mid,k*2,x,y); else if(x>mid) return query(mid+1,r,k*2+1,x,y); else { int ls=query_r(l,mid,k*2,x,mid); int rs=query_l(mid+1,r,k*2+1,mid+1,y); return max(max(query(l,mid,k*2,x,mid),query(mid+1,r,k*2+1,mid+1,y)),ls+rs); } } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]),s[i]=s[i-1]+a[i]; build(1,n,1); scanf("%d",&m); for(int i=1;i<=m;i++){ int x,y;scanf("%d%d",&x,&y); printf("%d ",query(1,n,1,x,y)); } return 0; }