洛谷P4513 小白逛公园

洛谷P4513 小白逛公园

题解

这道题需要求最大子段和,还需要支持单点修改操作,我们可以考虑用线段树。

对于每个区间,维护四个值:

  • s u m sum sum,表示区间和
  • m a x max max,表示区间最大子段和
  • m a x l maxl maxl,表示包含左端点的区间最大子段和
  • m a x r maxr maxr,表示包含右端点的区间最大子段和

注意最大子段和至少包含一个元素。

修改时,更新四个值,操作如下:

  • 更新 m a x max max时还要用左儿子的 m a x r maxr maxr和右儿子的 m a x l maxl maxl更新。若两者都为负,则取最大值;否则取两个之中所有的正数
  • 用左右儿子的 m a x max max更新该节点的 m a x max max
  • m a x l maxl maxl为左儿子的 m a x l maxl maxl和左儿子的 s u m sum sum加右儿子的 m a x l maxl maxl二者的最大值
  • m a x r maxr maxr为右儿子的 m a x r maxr maxr和右儿子的 s u m sum sum加左儿子的 m a x r maxr maxr二者的最大值
  • s u m sum sum为左右儿子的 s u m sum sum的和

查询时,操作如下:

  • 如果当前节点的区间被查询区间覆盖,则返回该节点的信息
  • 如果查询区间只与该节点的一个儿子有交集,则返回查询这个儿子得到的信息
  • 如果查询区间与该节点的两个儿子都有交集,则分别查询两个儿子的信息,再用修改时更新的方式将两个信息合并,将合并后的信息返回

为了方便查询,答案 a n s ans ans用结构体存储,最终输出 a n s . m a x ans.max ans.max

code

#include
#define lc k<<1
#define rc k<<1|1
using namespace std;
long long a[500005];
struct node{
	int sum,mxl,mxr,mx;
}tr[2000005];
void pushup(node &vk,node vl,node vr){
	int vt;
	if(vl.mxr<0&&vr.mxl<0) vt=max(vl.mxr,vr.mxl);
	else vt=max(0,vl.mxr)+max(0,vr.mxl);
	vk.sum=vl.sum+vr.sum;
	vk.mxl=max(vl.mxl,vl.sum+vr.mxl);
	vk.mxr=max(vr.mxr,vr.sum+vl.mxr);
	vk.mx=max(vt,max(vl.mx,vr.mx));
}
void build(int k,int l,int r){
	if(l==r){
		tr[k]=(node){a[l],a[l],a[l],a[l]};
		return;
	}
	int mid=l+r>>1;
	build(lc,l,mid);build(rc,mid+1,r);
	pushup(tr[k],tr[lc],tr[rc]);
}
void ch(int k,int l,int r,int x,int e){
	if(l==r&&l==x){
		tr[k]=(node){e,e,e,e};
		return;
	}
	int mid=l+r>>1;
	if(x<=mid) ch(lc,l,mid,x,e);
	else ch(rc,mid+1,r,x,e);
	pushup(tr[k],tr[lc],tr[rc]);
}
node find(int k,int l,int r,int x,int y){
	if(l>=x&&r<=y) return tr[k];
	int mid=l+r>>1;
	if(x<=mid&&mid<y){
		node re;
		pushup(re,find(lc,l,mid,x,y),find(rc,mid+1,r,x,y));
		return re;
	}
	if(x<=mid) return find(lc,l,mid,x,y);
	if(y>mid) return find(rc,mid+1,r,x,y);
}
int main()
{
	int n,m,k,x,y;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
	}
	build(1,1,n);
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&k,&x,&y);
		if(k==1){
			if(x>y) swap(x,y);
			printf("%d\n",find(1,1,n,x,y).mx); 
		}
		else ch(1,1,n,x,y);
	}
	return 0;
}

你可能感兴趣的:(题解,c++)