線段樹區間最大子段和

線段樹區間最大子段和

應用場景

支持單點修改時維護區間的最大字段和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;
}
相關文章
相關標籤/搜索