传送门

题面

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

题解

线段树好题,建议先做SP1043 GSS1 - Can you answer these queries I

首先分析两线段相离的情况,发现[y1+1,x21][y1+1,x2-1]是必选区间

然后分析两线段相交的情况:

有三种情况

  • 端点在[x2,y1][x2,y1],只用求[x2,y1][x2,y1]区间子段最大值
  • 左端点在[x1,x21][x1,x2-1],右端点在[x2,y2][x2,y2],按照线段相离的方法来求
  • 左端点在[x1,y1][x1,y1],右端点在[x1+1,y2][x1+1,y2],同理

p.s.p.s.可能cmathcmath不支持y1y1,我把x1,y1,x2,y2x1,y1,x2,y2换成了l1,r1,l2,r2l1,r1,l2,r2

#include <bits/stdc++.h>
#define MAXN 50005
using namespace std;
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while (ch<'0'||ch>'9'){
        if (ch=='-') f=-1;
        ch=getchar();
    }
    while (ch>='0'&&ch<='9'){
        x=(x<<3)+(x<<1)+(ch^'0');
        ch=getchar();
    }
    return x*f;
}
int a[MAXN];
namespace SegmentTree{
    struct node{
        int l,r;
        int lmax,rmax,maxn;//从左端开始最大值,从右端开始最大值,整段最大值
        int val;//这段的和
    }tree[MAXN<<2];
    node empty_node(){
        node temp;
        temp.l=temp.r=temp.lmax=temp.rmax=temp.maxn=temp.val=0;
        return temp;
    }
    void Init(){
        memset(tree,0,sizeof(tree));
    }
    #define lc i<<1
    #define rc i<<1|1
    node operator + (node A,node B){
        node temp;
        temp.lmax=max(B.lmax+A.val,A.lmax);
        temp.rmax=max(A.rmax+B.val,B.rmax);
        temp.maxn=max(max(A.maxn,B.maxn),A.rmax+B.lmax);
        temp.val=A.val+B.val;
        temp.l=A.l,temp.r=B.r;
        return temp;
    }
    void pushup(int i){
        tree[i]=tree[lc]+tree[rc];
    }
    void Build(int l,int r,int i){
        if (l==r){
            tree[i].lmax=tree[i].rmax=tree[i].maxn=tree[i].val=a[l];
            tree[i].l=tree[i].r=l;
            return ;
        }
        int mid=(l+r)>>1;
        Build(l,mid,lc);
        Build(mid+1,r,rc);
        pushup(i);
    }
    node TEMPQuery(int L,int R,int i){
        if (L>R) return empty_node();//特判L>R情况
        if (L<=tree[i].l&&tree[i].r<=R){
            return tree[i];
        }
        int mid=(tree[i].l+tree[i].r)>>1;
        if (L>mid) return TEMPQuery(L,R,rc);
        else if (R<=mid) return TEMPQuery(L,R,lc);
        else return TEMPQuery(L,R,lc)+TEMPQuery(L,R,rc);
    }
    node Query(int L,int R){
        return TEMPQuery(L,R,1);
    }
};
using namespace SegmentTree;
inline int Get_Ans(int l1,int r1,int l2,int r2){//r1<=l2即区间[l1,r1],[l2,r2]相离或相切
    if (r1==l2) return Query(l1,r1).rmax+Query(l2,r2).lmax-a[r1];//相切特殊情况
    return Query(l1,r1).rmax+Query(r1+1,l2-1).val+Query(l2,r2).lmax;
}
inline int Solve(int l1,int r1,int l2,int r2){
    if (l1==l2&&r1==r2){
        return Query(l1,r1).maxn;
    }
    if (r1<l2){
        return Get_Ans(l1,r1,l2,r2);
    }
    else {
        int ans=Query(l2,r1).maxn;
        ans=max(ans,Get_Ans(l1,l2,l2,r2));
        ans=max(ans,Get_Ans(l1,r1,r1,r2));
        return ans;
    }
}
int main(){
    int Case=read();
    for (register int k=1;k<=Case;++k){
        int n=read();
        for (register int i=1;i<=n;++i){
            a[i]=read();
        }
        Init();
        Build(1,n,1);
        int q=read();
        while (q--){
            int l1=read(),r1=read(),l2=read(),r2=read();
            printf("%d\n",Solve(l1,r1,l2,r2));
        }
    }
}