SPOJ GSS5 Can you answer these queries V 线段树

$ \Rightarrow $ 戳我进SPOJ原题

GSS5 - Can you answer these queries V

 

Time limit: 0.132s $ \quad $ Source limit: 50000B $ \quad $ Memory limit:1536MB

  You are given a sequence A[1], A[2], ..., A[N] . ( |A[i]| <= 10000 , 1 <= N <= 10000 ). A query is defined as follows: Query(x1,y1,x2,y2) = Max { A[i]+A[i+1]+...+A[j] ; x1 <= i <= y1 , x2 <= j <= y2 and x1 <= x2 , y1 <= y2 }. Given M queries (1 <= M <= 10000), your program must output the results of these queries.  

Input

The first line of the input consist of the number of tests cases <= 5. Each case consist of the integer N and the sequence A.
Then the integer M. M lines follow, contains 4 numbers x1, y1, x2 y2.
 

Output

Your program should output the results of the M queries for each test case, one query per line.
 

Examples

 Input:
 2
 6 3 -2 1 -4 5 2
 2
 1 1 2 3
 1 3 2 5
 1 1
 1
 1 1 1 1

 Output:
 2
 3
 1

 

题意翻译

给定一个序列。查询左端点在 $ [x_1, y_1] $ 之间,且右端点在 $ [x_2, y_2] $ 之间的最大子段和,
数据保证 $ x_1\leq x_2,y_1\leq y_2 $ ,但是不保证端点所在的区间不重合

感谢@Anoxiacxy 提供的翻译
 

思路

  • 如果 $ x_1 \le y_1 <x_2 \le y_2 $

    • 区间分离,中间必须取,两端区间靠近中间选最大
       
  • 如果 $ x_1 \le x_2 \le y_1 \le y_2 $

    • 选取 $ [x_2,y_1] $ 中的最大子段和
      选取 $ [x_1,x_2-1] $ 的最右端部分,和 $ [x_2,y_1] $ 的最左端部分
      选取 $ [x_2,y_1] $ 的最右端部分,和 $ [y_1+1,y_2] $ 的最左端部分
      选取 $ [x_1,x_2-1] $ 的最右端部分,$ [x_2,y_1] $ 的全部,和 $ [y_1+1,y_2] $ 的最左端部分
       

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 100010
#define int long long
struct tree{ int l,r,lmax,rmax,max,sum; }t[maxn<<2];
int T,n,m,x1,x2,y1,y2,s[maxn],ans;
void pushup(int o){
    t[o].sum=t[o<<1].sum+t[o<<1|1].sum;
    t[o].lmax=max(t[o<<1].sum+t[o<<1|1].lmax,t[o<<1].lmax);
    t[o].rmax=max(t[o<<1|1].sum+t[o<<1].rmax,t[o<<1|1].rmax);
    t[o].max=max(t[o<<1].rmax+t[o<<1|1].lmax,max(t[o<<1].max,t[o<<1|1].max));
}
void build(int o,int l,int r){
    t[o].l=l; t[o].r=r;
    if(l==r){ 
        scanf("%lld",&t[o].sum); 
        s[l]=s[l-1]+t[o].sum;
        t[o].max=t[o].lmax=t[o].rmax=t[o].sum;
        return;
    }
    int mid=l+r>>1;
    build(o<<1,l,mid); build(o<<1|1,mid+1,r);
    pushup(o);
}
int ql(int o,int l,int r){
    if(l>r) return 0;
    if(t[o].l==l&&t[o].r==r) return t[o].lmax;
    int mid=t[o].l+t[o].r>>1;
    if(l>mid) return ql(o<<1|1,l,r);
    else if(r<=mid) return ql(o<<1,l,r);
    else return max(ql(o<<1,l,mid),s[mid]-s[l-1]+ql(o<<1|1,mid+1,r));
}
int qr(int o,int l,int r){
    if(l>r) return 0;
    if(t[o].l==l&&t[o].r==r) return t[o].rmax;
    int mid=t[o].l+t[o].r>>1;
    if(l>mid) return qr(o<<1|1,l,r);
    else if(r<=mid) return qr(o<<1,l,r);
    else return max(qr(o<<1|1,mid+1,r),s[r]-s[mid]+qr(o<<1,l,mid));
}
int qm(int o,int l,int r){
    if(l>r) return 0;
    if(t[o].l==l&&t[o].r==r) return t[o].max;
    int mid=t[o].l+t[o].r>>1;
    if(l>mid) return qm(o<<1|1,l,r);
    else if(r<=mid) return qm(o<<1,l,r);
    else {
        int Lmax=ql(o<<1|1,mid+1,r);
        int Rmax=qr(o<<1,l,mid);
        return max(Lmax+Rmax,max(qm(o<<1,l,mid),qm(o<<1|1,mid+1,r)));
    }
}
signed main(){
    scanf("%lld",&T);
    while(T--){
        scanf("%lld",&n);
        build(1,1,n);
        scanf("%lld",&m);
        while(m--){
            scanf("%lld %lld %lld %lld",&x1,&y1,&x2,&y2);
            if(x2>y1){
                ans=s[x2-1]-s[y1];
                ans+=qr(1,x1,y1)+ql(1,x2,y2);
                printf("%lld\n",ans);
            } else {
                ans=qm(1,x2,y1);
                ans=max(ans,qr(1,x2,y1)+ql(1,y1+1,y2));
                ans=max(ans,ql(1,x2,y1)+qr(1,x1,x2-1));
                ans=max(ans,qr(1,x1,x2-1)+s[y1]-s[x2-1]+ql(1,y1+1,y2));
                printf("%lld\n",ans);
            }
        }
    }
    return 0;
}
posted @ 2018-09-19 15:24  potrem  阅读(158)  评论(0编辑  收藏  举报