33

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

 3 years ago
source link: http://www.cnblogs.com/liuchanglc/p/13551819.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

题目描述

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

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

《山海经》是以山为纲,以海为线记载古代的河流、植物、动物及矿产等情况,而且每一条记录路线都不会有重复的山出现。某天,你的地理老师想重游《山海经》中的路线,为了简化问题,老师已经把每座山用一个整数表示他对该山的喜恶程度,他想知道第 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

样例输出

分析

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

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

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

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

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

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

代码

#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;
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK