[未知OJ]山海经 题解 线段树

题意:给出一个数列a(n<=1e5),每次询问区间[l..r]的最大连续子段和,以及这个连续子段的两个端点。如果有多组解,则输出左端点最小的,如果仍有多组解,则输出右端点最小的解。

此题有简单版

这题毒瘤就毒瘤在求这两个端点。对于线段树的每个节点,除了记录区间和,前缀最大和,后缀最大和,最大连续子段和,还要分别记录前缀最大和,后缀最大和,最大连续子段和的端点,似乎这题码量算少的?

#include<bits/stdc++.h>
using namespace std;
#define scanf a1234=scanf
int a1234;

const int mxn=1e5+3;int n,T,a[mxn];
struct tourist{
    int lnum,rnum,sum,num,ll,rr,ln,rn;
//ll是lnum的端点 rr是rnum的端点 ln rn是num的端点
    inline void pr(int l,int r){
        printf("%d %d %d %d %d %d %d %d %d %d\n",l,r,lnum,rnum,sum,num,ll,rr,ln,rn);
    }
};

#define mid ((l+r)>>1)
class segm{
    public:
    tourist tr[mxn*4];
    inline void Build(int x,int l,int r){
        if(l==r)return tr[x]={a[l],a[l],a[l],a[l],l,l,l,l},void();
        Build(x*2,l,mid),Build(x*2+1,mid+1,r);
        up(x);
    }
    inline void up(int x){
        tr[x]=merge(tr[x*2],tr[x*2+1]);
    }
    inline tourist merge(tourist &a,tourist &b){
        static tourist res;
        res.sum=a.sum+b.sum;
        int aa=a.lnum,bb=a.sum+b.lnum;
        if(aa>=bb)res.lnum=aa,res.ll=a.ll;else res.lnum=bb,res.ll=b.ll;
        aa=b.rnum,bb=b.sum+a.rnum;
        if(bb>=aa)res.rnum=bb,res.rr=a.rr;else res.rnum=aa,res.rr=b.rr;
        
        
        aa=a.num,bb=b.num;
        if(aa>=bb)res.num=aa,res.ln=a.ln,res.rn=a.rn;
        else      res.num=bb,res.ln=b.ln,res.rn=b.rn;
        aa=a.rnum+b.lnum; int ll=a.rr,rr=b.ll;
        if(aa>res.num|| (aa==res.num&&ll<res.ln) /*|| (aa==res.num&&ll==res.ln&&rr<res.rn)*/)res.num=aa,res.ln=ll,res.rn=rr;
        return res;
    }
    inline tourist qask(int x,int l,int r,int lc,int rc){   
        if(lc<=l&&r<=rc)return tr[x];
        if(lc>mid)return qask(x*2+1,mid+1,r,lc,rc);
        if(rc<=mid)return qask(x*2,l,mid,lc,rc);
        tourist lres=qask(x*2,l,mid,lc,rc),rres=qask(x*2+1,mid+1,r,lc,rc);
        return merge(lres,rres);
    }
}seg;
#undef mid

int main(){
    scanf("%d%d",&n,&T);for(int i=1;i<=n;++i)scanf("%d",a+i);
    seg.Build(1,1,n);
    while(T--){
       int l,r;scanf("%d%d",&l,&r);
       static tourist tql; tql=seg.qask(1,1,n,l,r);
       printf("%d %d %d\n",tql.ln,tql.rn,tql.num);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/happyguy/p/13379620.html