SP2916 GSS5 - Can you answer these queries V

博客围绕给定序列,求解左端点在[x1,y1]、右端点在[x2,y2]间的最大子段和问题展开。题解指出这是线段树好题,先建议做相关题目,接着分别分析两线段相离和相交情况,相交时有三种情况并给出求解思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题面

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

题解

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

首先分析两线段相离的情况,发现 [ y 1 + 1 , x 2 − 1 ] [y1+1,x2-1] [y1+1,x21]是必选区间
在这里插入图片描述

然后分析两线段相交的情况:
在这里插入图片描述
有三种情况

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

p . s . p.s. p.s.可能 c m a t h cmath cmath不支持 y 1 y1 y1,我把 x 1 , y 1 , x 2 , y 2 x1,y1,x2,y2 x1,y1,x2,y2换成了 l 1 , r 1 , l 2 , r 2 l1,r1,l2,r2 l1,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));
        }
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值