山海经:线段树维护最大子段和

题目描述

“南山之首日鹊山。其首日招摇之山,临于西海之上,多桂,多金玉。有草焉,其状如韭而青华,其名日祝余,食之不饥……又东三百里,日堂庭之山,多棪木,多白猿,多水玉,多黄金。

又东三百八十里,日猨翼之山,其中多怪兽,水多怪鱼,多白玉,多蝮虫,多怪蛇,名怪木,不可以上。……”

《山海经》是以山为纲,以海为线记载古代的河流、植物、动物及矿产等情况,而且每一条记录路线都不会有重复的山出现。某天,你的地理老师想重游《山海经》中的路线,为了简化问题,老师已经把每座山用一个整数表示他对该山的喜恶程度,他想知道第a座山到第b座山的中间某段路(i,j)。能使他感到最满意,即(i,j)这条路上所有山的喜恶度之和是(c,d)(a≤c≤d≤b)最大值。

于是老师便向你请教,你能帮助他吗?值得注意的是,在《山海经》中,第i座山只能到达第i+1座山。

输入格式

输入第1行是两个数,n,m,2≤n≤100000,1≤m≤100000n表示一共有n座山,m表示老师想查询的数目。

2行是n个整数,代表n座山的喜恶度,绝对值均小于10000

以下m行每行有a,b两个数,1≤a≤j≤b≤m,表示第a座山到第b座山。

输出格式

一共有m行,每行有3个数i,j,s,表示从第i座山到第j座山总的喜恶度为s。显然,对于每个查询,有a≤i≤j≤b,如果有多组解,则输出i最小的,如果i也相等,则输出j最小的解。

样例

样例输入

5 3
5 -6 3 -1 4
1 3
1 5
5 5

样例输出

1 1 5
3 5 6
5 5 4

分析

题意就是让你维护区间最大子段和,如果有多个,输出最靠左的那一个

线段树要维护区间左端点、右端点、最大子段和、最大前缀和、最大后缀和、最大子段和的左右端点、最大前缀和的右端点、最大后缀和的左端点、区间和

合并时,区间最大子段和:左区间最大子段和、右区间最大子段和、左区间最大后缀和+右区间最大前缀和

区间最大前缀和:左区间最大前缀和、左区间和+右区间最大前缀和

区间最大后缀和:右区间最大后缀和、左区间最大后缀和+右区间和

注意更新最大子段和的端点时要注意最左端的优先

代码

#include<cstdio>
const int maxn=1e6+5;
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<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*f;
}
struct trr{
    int l,r,mmax,lmax,rmax,jll,jlr,zb,yb,sum;
    trr(){
        mmax=rmax=lmax=-0x3f3f3f3f;
        jll=zb=0x3f3f3f3f;
        jlr=yb=-0x3f3f3f3f;
    }
}tr[maxn];
int a[maxn],n,m;
trr push_up(trr aa,trr bb){
    trr now;
    now.l=aa.l,now.r=bb.r;
    now.sum=aa.sum+bb.sum;
    if(now.mmax<aa.mmax || (now.mmax==aa.mmax && now.jll>aa.jll)){
        now.mmax=aa.mmax;
        now.jll=aa.jll;
        now.jlr=aa.jlr;
    }
    if(now.mmax<bb.mmax || (now.mmax==bb.mmax && now.jll>bb.jll)){
        now.mmax=bb.mmax;
        now.jll=bb.jll;
        now.jlr=bb.jlr;
    }
    if(now.mmax<aa.rmax+bb.lmax || (now.mmax==aa.rmax+bb.lmax && now.jll>aa.yb)){
        now.mmax=aa.rmax+bb.lmax;
        now.jll=aa.yb;
        now.jlr=bb.zb;
    } 
    now.lmax=aa.lmax,now.zb=aa.zb;
    if(aa.sum+bb.lmax>now.lmax){
        now.lmax=aa.sum+bb.lmax;
        now.zb=bb.zb;
    }
    now.rmax=bb.rmax,now.yb=bb.yb;
    if(aa.rmax+bb.sum>=now.rmax){
        now.rmax=aa.rmax+bb.sum;
        now.yb=aa.yb;
    }
    return now;
}
void build(int da,int l,int r){
    tr[da].l=l,tr[da].r=r;
    if(l==r){
        tr[da].mmax=tr[da].lmax=tr[da].rmax=tr[da].sum=a[l];
        tr[da].jll=tr[da].jlr=tr[da].zb=tr[da].yb=l;
        return;
    }
    int mids=(tr[da].l+tr[da].r)>>1;
    build(da<<1,l,mids);
    build(da<<1|1,mids+1,r);
    tr[da]=push_up(tr[da<<1],tr[da<<1|1]);
}
trr cx(int da,int l,int r){
    if(tr[da].l>=l && tr[da].r<=r){
        return tr[da];
    }
    int mids=(tr[da].l+tr[da].r)>>1;
    if(l>mids) return cx(da<<1|1,l,r);
    else if(r<=mids) return cx(da<<1,l,r);
    else return push_up(cx(da<<1,l,r),cx(da<<1|1,l,r));
}
int main(){
    n=read(),m=read();
    for(int i=1;i<=n;i++){
        a[i]=read();
    }
    build(1,1,n);
    for(int i=1;i<=m;i++){
        int l,r;
        l=read(),r=read();
        trr now=cx(1,l,r);
        printf("%d %d %d\n",now.jll,now.jlr,now.mmax);
    }
    return 0;
}

posted @ 2020-08-24 07:50  liuchanglc  阅读(351)  评论(0编辑  收藏  举报