GSS3 - Can you answer these queries III

题目

GSS3 - Can you answer these queries III_第1张图片

思路

因为是区间查询,我们用线段树维护
为了求最大子段和(mfa),有几种情况?
将一个区间分成L,R
GSS3 - Can you answer these queries III_第2张图片

情况①

最大子段和全在L
GSS3 - Can you answer these queries III_第3张图片

情况②

最大子段和全在R
GSS3 - Can you answer these queries III_第4张图片

情况③

最大子段和在LR中间
GSS3 - Can you answer these queries III_第5张图片
可以看到,这种情况下的最大字段和由两部分——L最大后缀和(suf)和R最大前缀和(pre)构成
所以得出 x . m f a = m a x { l c . m f a , r c . m f a , l c . s u f + r c . p r e } x.mfa=max\{lc.mfa,rc.mfa,lc.suf+rc.pre\} x.mfa=max{lc.mfa,rc.mfa,lc.suf+rc.pre}

所以,我们现在要维护的多了suf和pre
来看看求pre的情况

情况①

只在L
GSS3 - Can you answer these queries III_第6张图片

情况②

L的全部和R
GSS3 - Can you answer these queries III_第7张图片
由此我们得出 x . p r e = m a x { l c . p r e , l c . s u m + r c . p r e } x.pre=max\{lc.pre,lc.sum+rc.pre\} x.pre=max{lc.pre,lc.sum+rc.pre}
同样地,我们也可以得出 x . s u f = m a x { r c . s u f , l c . s u f + r c . s u m } x.suf=max\{rc.suf,lc.suf+rc.sum\} x.suf=max{rc.suf,lc.suf+rc.sum}

至此,我们得出需要维护的有四个: m f a , s u f , p r e , s u m mfa,suf,pre,sum mfa,suf,pre,sum
用结构体存一下
理论存在,实践开始

代码

#include 
using namespace std;
const int M = 1e5+10;
int a[M],n,m;
struct node{
	int mfa,pre,suf,sum;
};
struct segment{
	#define rc ((x<<1)|1)//左右结点
	#define lc (x<<1)
	node seg[M<<2];
	void pushup(int x){//需要维护的
		seg[x].sum=seg[lc].sum+seg[rc].sum;//区间和
		seg[x].pre=max(seg[lc].pre,seg[lc].sum+seg[rc].pre);//最大前缀和
		seg[x].suf=max(seg[rc].suf,seg[rc].sum+seg[lc].suf);//最大后缀和
		seg[x].mfa=max(max(seg[lc].mfa,seg[rc].mfa),seg[lc].suf+seg[rc].pre);//最大子段和
	}
	void build(int x,int l,int r){//建树
		if(l==r){
			seg[x].mfa=seg[x].pre=seg[x].suf=seg[x].sum=a[l];
			return;
		}
		int mid=l+r>>1;
		build(lc,l,mid),build(rc,mid+1,r);
		pushup(x);
	}
	void update(int x,int l,int r,int o,int k){//修改操作
		if(l==r&&l==o){
			seg[x].mfa=seg[x].pre=seg[x].suf=seg[x].sum=k;
			return;
		}
		if(o<l||r<o) return;
		int mid=l+r>>1;
		update(lc,l,mid,o,k),update(rc,mid+1,r,o,k);
		pushup(x);
	}
	node query(int x,int ql,int qr,int l,int r){//查询操作
		if(ql<=l&&r<=qr) return seg[x];
		bool f1=0,f2=0;
		node left,right;
		int mid=l+r>>1;
		if(ql<=mid) left=query(lc,ql,qr,l,mid),f1=1;
		if(mid+1<=qr) right=query(rc,ql,qr,mid+1,r),f2=1;
		node ans;
		if(f1&&f2){//如果L,R内都有
			ans.sum=left.sum+right.sum;
			ans.pre=max(left.pre,left.sum+right.pre);
			ans.suf=max(right.suf,right.sum+left.suf);
			ans.mfa=max(max(left.mfa,right.mfa),left.suf+right.pre);
		}
		else if(f1) ans=left;
		else ans=right;
		return ans;
	}
}T;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	cin>>m;
	T.build(1,1,n);
	while(m--){
		int if_case;
		cin>>if_case;
		int x,y;
		cin>>x>>y;
		switch (if_case){
			case 1:cout<<T.query(1,x,y,1,n).mfa<<endl;break;
			case 0:T.update(1,1,n,x,y);break;
		}
	}
	return 0;
}

你可能感兴趣的:(算法,c++,线段树,数据结构,刘汝佳)