SP1043 GSS1 - Can you answer these queries I

线段树每个节点中存的值:

v a l [ ] val[] val[] ——区间所有数之和

l m a x [ ] lmax[] lmax[] ——选的 a [ i ] a[i] a[i]在区间内,且包括 a [ l ] a[l] a[l],连续 a [ i ] a[i] a[i]之和的最大值

r m a x [ ] rmax[] rmax[] ——选的 a [ i ] a[i] a[i]在区间内,且包括 a [ r ] a[r] a[r],连续 a [ i ] a[i] a[i]之和的最大值

m a x n [ ] maxn[] maxn[] ——选的 a [ i ] a[i] a[i]在区间内,连续 a [ i ] a[i] a[i]之和的最大值(即本题答案)

之所以要计算 l m a x lmax lmax r m a x rmax rmax v a l val val,是为了合并节点时,能计算出 m a x n maxn maxn的值


这里介绍一种比较简洁的写法

这道题中线段树的重点是节点合并,即 p u s h u p pushup pushup的过程

不妨将节点合并的操作定义为+

这样Query时就不用再敲一遍相同的代码,直接将查询结果相"+"即可

#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];
    #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);
        //可以左区间全部选,加上右区间lmax,也可以直接用左区间lmax
        temp.rmax=max(A.rmax+B.val,B.rmax);
        //同理
        temp.maxn=max(max(A.maxn,B.maxn),A.rmax+B.lmax);
        //可以直接用左右区间maxn,也可以将左右区间rmax,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 Query(int L,int R,int i){
        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 Query(L,R,rc);
        else if (R<=mid) return Query(L,R,lc);
        else return Query(L,R,lc)+Query(L,R,rc);
        //这里就不用再重复一遍节点合并的过程
    }
};
using namespace SegmentTree;
int main(){
    int n=read();
    for (register int i=1;i<=n;++i){
        a[i]=read();
    }
    Build(1,n,1);
    int q=read();
    while (q--){
        int L=read(),R=read();
        node temp=Query(L,R,1);
        printf("%d\n",temp.maxn);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值