Can you answer these queries(spoj 1043)

题意:多次查询区间最长连续字段和

/*
    用线段树维护区间最长子段和,最长左子段和,最长右子段和。 
*/
#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;
}
原文地址:https://www.cnblogs.com/harden/p/6395591.html