线段树区间最大子段和
应用场景
支持单点修改时维护区间的最大字段和node
核心思想
利用线段树的分治思想,区间内的子段能够分为彻底在左侧的,穿过中点的和彻底在右侧的。c++
实现
维护区间最大字段和基于不带lazy_tag的线段树,只须要将状态由和变为结构体便可。 首先,咱们定义一种结构体,包含区间和,从左侧开始的最大字段和,从右侧开始的最大字段和与没有要求的最大字段和。测试
struct node{ LL sum,maxl,maxr,maxv; node(){ sum=maxl=maxr=maxv=0; } };
对于一个区间,咱们只须要将其分红左右两个部分,按照下面的代码更新便可。spa
inline void push_up(int x){ A[x].sum=A[x<<1].sum+A[x<<1|1].sum; A[x].maxl=max(A[x<<1].maxl,A[x<<1].sum+A[x<<1|1].maxl); A[x].maxv=max(A[x<<1].maxr+A[x<<1|1].maxl,max(A[x<<1].maxv,A[x<<1|1].maxv)); A[x].maxr=max(A[x<<1|1].maxr,A[x<<1].maxr+A[x<<1|1].sum); }
在操做中,建树、单点修改都是正常的,只须要设计区间查询最大字段和。 此处咱们返回一个结构体,包含查询范围内的状态,每次按照分治的规则归并便可设计
node query(int x,int l,int r,int ql,int qr){ if(ql<=l&&r<=qr){ return A[x]; } int mid=(l+r)>>1; if(qr<=mid) return query(x<<1,l,mid,ql,qr); if(ql>mid) return query(x<<1|1,mid+1,r,ql,qr); node left=query(x<<1,l,mid,ql,qr),right=query(x<<1|1,mid+1,r,ql,qr),ret; ret.maxv=max(left.maxr+right.maxl,max(left.maxv,right.maxv)); ret.maxl=max(left.maxl,left.sum+right.maxl); ret.maxr=max(right.maxr,left.maxr+right.sum); return ret; }
例题
[Luogu P4513 小白逛公园](%3Ca href="https://www.luogu.org/problemnew/show/P4513"%3Ehttps://www.luogu.org/problemnew/show/P4513%3C/a%3E)
题目描述
在小新家附近有一条“公园路”,路的一边从南到北依次排着nn个公园,小白早就看花了眼,本身也不清楚该去哪些公园玩了。一开始,小白就根据公园的风景给每一个公园打了分-.-。小新为了省事,每次遛狗的时候都会事先规定一个范围,小白只能够选择第aa个和第bb个公园之间(包括aa、bb两个公园)选择连续的一些公园玩。小白固然但愿选出的公园的分数总和尽可能高咯。同时,因为一些公园的景观会有所改变,因此,小白的打分也可能会有一些变化。那么,就请你来帮小白选择公园吧。code
输入输出格式
输入格式:
第一行,两个整数NN和MM,分别表示表示公园的数量和操做(遛狗或者改变打分)总数。 接下来NN行,每行一个整数,依次给出小白 开始时对公园的打分。 接下来MM行,每行三个整数。第一个整数KK,11或22。K=1K=1表示,小新要带小白出去玩,接下来的两个整数aa和bb给出了选择公园的范围(1≤a,b≤N1≤a,b≤N)。测试数据可能会出现a>ba>b的状况,须要进行交换;K=2K=2表示,小白改变了对某个公园的打分,接下来的两个整数pp和ss,表示小白对第pp个公园的打分变成了ss(1≤p≤N1≤p≤N)。 其中,1≤N≤500 0001≤N≤500000,1≤M≤100 0001≤M≤100000,全部打分都是绝对值不超过10001000的整数。get
输出格式:
小白每出去玩一次,都对应输出一行,只包含一个整数,表示小白能够选出的公园得分和的最大值。输入输出样例输入样例#1: 5 3 1 2 -3 4 5 1 2 3 2 2 -1 1 2 3 输出样例#1: 2 -1it
题解
这道题是模板题,直接给出代码模板
using namespace std; typedef long long LL; const int INF=1e9+7,MAXN=5e5+10,MAXNODE=MAXN<<2,MAXM=1e5+10; int N,M; LL tmp[MAXN]; struct node{ LL sum,maxl,maxr,maxv; node(){ sum=maxl=maxr=maxv=0; } }A[MAXNODE]; inline void push_up(int x){ A[x].sum=A[x<<1].sum+A[x<<1|1].sum; A[x].maxl=max(A[x<<1].maxl,A[x<<1].sum+A[x<<1|1].maxl); A[x].maxv=max(A[x<<1].maxr+A[x<<1|1].maxl,max(A[x<<1].maxv,A[x<<1|1].maxv)); A[x].maxr=max(A[x<<1|1].maxr,A[x<<1].maxr+A[x<<1|1].sum); } void init(int x,int l,int r){ if(l==r){ A[x].sum=A[x].maxl=A[x].maxr=A[x].maxv=tmp[l]; return; } int mid=(l+r)>>1; init(x<<1,l,mid); init(x<<1|1,mid+1,r); push_up(x); } void update(int x,int l,int r,int q,LL c){ if(l==r){ if(l==q) A[x].sum=A[x].maxl=A[x].maxr=A[x].maxv=c; return; } int mid=(l+r)>>1; if(q<=mid) update(x<<1,l,mid,q,c); else update(x<<1|1,mid+1,r,q,c); push_up(x); } node query(int x,int l,int r,int ql,int qr){ if(ql<=l&&r<=qr){ return A[x]; } int mid=(l+r)>>1; if(qr<=mid) return query(x<<1,l,mid,ql,qr); if(ql>mid) return query(x<<1|1,mid+1,r,ql,qr); node left=query(x<<1,l,mid,ql,qr),right=query(x<<1|1,mid+1,r,ql,qr),ret; ret.maxv=max(left.maxr+right.maxl,max(left.maxv,right.maxv)); ret.maxl=max(left.maxl,left.sum+right.maxl); ret.maxr=max(right.maxr,left.maxr+right.sum); return ret; } int main(){ scanf("%d%d",&N,&M); for(int i=1;i<=N;i++) scanf("%lld",tmp+i); init(1,1,N); int ii,jj,kk; LL ll; for(int i=1;i<=M;i++){ scanf("%d",&ii); if(ii==1){ scanf("%d%d",&jj,&kk); if(jj>kk) swap(jj,kk); printf("%lld\n",query(1,1,N,jj,kk).maxv); }else{ scanf("%d%lld",&jj,&ll); update(1,1,N,jj,ll); } } return 0; }