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


    题目描述

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

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

    《山海经》是以山为纲,以海为线记载古代的河流、植物、动物及矿产等情况,而且每一条记录路线都不会有重复的山出现。某天,你的地理老师想重游《山海经》中的路线,为了简化问题,老师已经把每座山用一个整数表示他对该山的喜恶程度,他想知道第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
    ",now.jll,now.jlr,now.mmax);
        }
        return 0;
    }
    
    
  • 相关阅读:
    最近忙于开发移动OA审批
    开发一个小软件
    VMWare上虚拟机访问宿主机需要注意的一个问题
    Visual Studio 中自带的电子邮件的正则表达式匹配中文的问题 与 \w
    开始应用设计模式
    jQuery与ASP.NET AJAX有冲突吗?
    有感于VMWare
    kvm 母镜像
    相关流程
    master事件处理
  • 原文地址:https://www.cnblogs.com/liuchanglc/p/13551819.html
Copyright © 2020-2023  润新知