LA 3938 动态最大连续和-线段树

博主分享做线段树题目求区间连续最大和的解题过程。先复习线段树专题,起初解题遇困难,参考网上代码后搞懂解法。介绍定义结构体、找区间连续最大和的三种可能情况,重点阐述询问区间的方法及计算最大后缀和、最大前缀和的拆分比较方式。

想了许久,最终决定写下这篇博文,这是我这周做的一道很不错的题目,线段树好神奇啊!,前一段时间复习了一下线段,找了找刘汝佳蓝书上线段树的专题做了做。这题让我卡了一天,自己先用了类似的方法,但是到询问的地方感觉怎么都写不对。后来我参考了一下网上的代码,终于搞懂刘所用到的解法了。

 

要做这一题,我们要先定义一个结构体

struct node{

pair<int,int>max_sub;//记录最大连续段的起点位置和终点位置

int max_perfix;//记录最大前缀和的终点位置

int max_suffix;//记录最大后缀和的起点位置

}

 

还需要搞懂一些数学知识

比如要找一个区间内连续最大和,有三种可能性

1连续最大和都在左子树区间内

2连续最大和都在右子树区间内

3连续最大和在整个区间内(左子树的最大后缀+右子树的最大前缀)

 

还有一点就是建树的时候前缀结束的位置和后缀开始的位置能提前尽量提前

接下来询问是重点

询问区间的时候

1如果当前区间是询问区间的子区间的话,则它的最大连续和则是它的解

2如果当前区间是有不完全的包含关系的话,则要比较左子树最大区间和,右子树最大区间和和区间x的最大区间和(x为[[qL,R1]中的最大后缀和,[L2,qR]中的最大前缀和])

 

最后提一下算[qL,R1]中的最大后缀和,[L2,qR]中的最大前缀和

1就是将[qL,R1]继续拆分,拆分为两个子区间,比较[qL,R3]中的最大后缀和+[L4,R4](R4==R1)和[L4,R4]中的最大后缀和

2就是将[L2,qR]继续拆分,拆分为两个子区间,比较[L6,qR]中的最大前缀和+[L5,R5](L5==L2)和[L5,R5]中的最大前缀和

 

这题也可以算是一道比较复杂的递归题

 

#include<cstdio>
#include<utility>
#define N 500005
using namespace std;
typedef long long LL;
LL m_sum[N];
int qL,qR;
struct node{
    int max_perfix;
    int max_suffix;
    pair<int, int>max_sub;
}node[4*N];
LL cacl_sum(int L,int R){
    return m_sum[R]-m_sum[L-1];
}
pair<int, int> better(pair<int, int>a,pair<int , int>b){
    if(cacl_sum(a.first, a.second)>cacl_sum(b.first, b.second))
        return a;
    else if(cacl_sum(a.first, a.second)<cacl_sum(b.first, b.second))
        return b;
    else if(a<b)
        return a;
    else
        return b;
}
void build(int o,int L,int R){
    if(L==R){
        node[o].max_perfix=node[o].max_suffix=L;
        node[o].max_sub=make_pair(L, L);
        return;
    }
    int mid=(L+R)/2;
    build(o*2, L, mid);
    build(o*2+1, mid+1, R);
    LL x1,x2;
    
    x1=cacl_sum(L, node[o*2].max_perfix);
    x2=cacl_sum(L, node[o*2+1].max_perfix);
    if(x1==x2)node[o].max_perfix=node[o*2].max_perfix;
    else if(x1>x2) node[o].max_perfix=node[o*2].max_perfix;
    else node[o].max_perfix=node[o*2+1].max_perfix;
    
    x1=cacl_sum(node[o*2].max_suffix,R);
    x2=cacl_sum(node[o*2+1].max_suffix,R);
    if(x1==x2)node[o].max_suffix=node[o*2].max_suffix;
    else if(x1>x2) node[o].max_suffix=node[o*2].max_suffix;
    else node[o].max_suffix=node[o*2+1].max_suffix;
    
    node[o].max_sub=better(node[o*2].max_sub, node[o*2+1].max_sub);
    node[o].max_sub=better(node[o].max_sub, make_pair(node[o*2].max_suffix, node[o*2+1].max_perfix));
}
pair<int, int>query_perfix(int o,int L,int R){
    if(qR>=node[o].max_perfix)return make_pair(L, node[o].max_perfix);
    int mid=(L+R)/2;
    if(qR<=mid)return query_perfix(o*2, L, mid);
    pair<int, int>x;
    x=query_perfix(o*2+1, mid+1, R);
    x.first=L;
    return better(make_pair(L,node[o*2].max_perfix), x);
}
pair<int, int>query_suffix(int o,int L,int R){
    if(qL<=node[o].max_suffix)return make_pair(node[o].max_suffix,R);
    int mid=(L+R)/2;
    if(qL>mid)return query_suffix(o*2+1, mid+1,R);
    pair<int, int>x;
    x=query_suffix(o*2, L, mid);
    x.second=R;
    return better(make_pair(node[o*2+1].max_suffix,R), x);
}
pair<int, int>query(int o,int L,int R){
    if(qL<=L&&qR>=R)
        return node[o].max_sub;
    int mid=(L+R)/2;
    if(qR<=mid) return query(o*2, L, mid);
    if(qL>mid) return query(o*2+1, mid+1, R);
    pair<int, int>x1,x2,x3;
    x1=query_suffix(o*2,L,mid);
    x2=query_perfix(o*2+1,mid+1,R);
    x3=better(query(o*2, L, mid), query(o*2+1,mid+1,R));
    return better(make_pair(x1.first, x2.second), x3);
}
int main(){
    int n,m,x,m_count=0;
    while (scanf("%d%d",&n,&m)!=EOF) {
        for(int i=1;i<=n;i++){
            scanf("%d",&x);
            m_sum[i]=m_sum[i-1]+x;
        }
        build(1, 1, n);
        printf("Case %d:\n",++m_count);
        while(m--){
            scanf("%d%d",&qL,&qR);
            pair<int, int>ans=query(1, 1, n);
            printf("%d %d\n",ans.first,ans.second);
        }
    }
    return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值