洛谷P4513 小白逛公园
这道题需要求最大子段和,还需要支持单点修改操作,我们可以考虑用线段树。
对于每个区间,维护四个值:
注意最大子段和至少包含一个元素。
修改时,更新四个值,操作如下:
查询时,操作如下:
为了方便查询,答案 a n s ans ans用结构体存储,最终输出 a n s . m a x ans.max ans.max。
#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;
}