1. 程式人生 > 實用技巧 >[未知OJ]山海經 題解 線段樹

[未知OJ]山海經 題解 線段樹

題意:給出一個數列a,每次詢問區間[l..r]的最大連續子段和,以及這個連續子段的兩個端點。如果有多組解,則輸出左端點最小的,如果仍有多組解,則輸出右端點最小的解。

我也不知道這題是哪個OJ的。。但是這題有個簡單版

這題毒瘤就毒瘤在求這兩個端點。對於線段樹的每個節點,除了記錄區間和,字首最大和,字尾最大和,最大連續子段和,還要分別記錄這幾種和的斷點。說起來挺容易,但是一到程式碼實現上,就變得非常詭異了。

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

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