题解
这道题需要求最大子段和,还需要支持单点修改操作,我们可以考虑用线段树。
对于每个区间,维护四个值:
- 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<bits/stdc++.h>
#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;
}
文章介绍了如何使用线段树数据结构来解决一个编程题目——求解最大子段和并支持单点修改。线段树中每个节点维护了四个值,包括区间和、区间最大子段和、包含左端点的最大子段和和包含右端点的最大子段和。在修改和查询时,都给出了相应的处理逻辑。
624

被折叠的 条评论
为什么被折叠?



