题意简化:
1.给出 $m$ 个询问:区间最大子段和。
2.可支持在线修改。
------------
Solution:
有一题 p1115 题意类似,只不过不支持修改,可以很容易得到 dp 方程:
dp[i]=max(dp[i-1]+a[i],a[i]);
但本题须支持修改,考虑用线段树维护。
线段树本质上将该数列不断分成更小的区间,最后再合并信息。
考虑一段区间 l~r,将其分成两个区间:l~mid,mid+1~r,那么对于该区间,答案一定为左区间,右区间,或两区间合起来中的一个。
即:
答案即为黄红紫三个区间中的一个,这也就说明了线段树需要保存的东西:区间最大:$maxn$,从左端点起向右的最大值:$lmax$,从右端点向左的最大值:$rmax$。
考虑如何维护 $lmax$,$rmax$:
例:
$lmax$ 取 max(左子树 $lmax$,左子树与右子树 $lmax$ 之和)。
$rmax$ 同理,故我们需维护区间和。
上代码(加注释):
#include<bits/stdc++.h> #define size 5001000 using namespace std; struct SegmentTree { int l,r,maxn,lmax,rmax,sum; }t[size<<2]; int n,m,hxt[size]; inline void pushup(int p) { t[p].sum=t[p<<1].sum+t[p<<1|1].sum; t[p].maxn=max(t[p<<1].maxn,max(t[p<<1|1].maxn,t[p<<1].rmax+t[p<<1|1].lmax)); t[p].lmax=max(t[p<<1].lmax,t[p<<1].sum+t[p<<1|1].lmax); t[p].rmax=max(t[p<<1|1].rmax,t[p<<1|1].sum+t[p<<1].rmax); }//上述维护lmax,rmax,maxn,sum的过程 inline void build(int l,int r,int p) { t[p].l=l,t[p].r=r; if(l==r) { t[p].sum=hxt[l]; t[p].lmax=hxt[l]; t[p].rmax=hxt[l]; t[p].maxn=hxt[l]; return; } int mid=(l+r)>>1; build(l,mid,p<<1); build(mid+1,r,p<<1|1); pushup(p); }//建树 inline void change(int pos,int d,int p) { if(t[p].l==t[p].r) { t[p].lmax=d; t[p].rmax=d; t[p].maxn=d; t[p].sum=d; return; } int mid=(t[p].l+t[p].r)>>1; if(pos<=mid) change(pos,d,p<<1); if(pos>mid) change(pos,d,p<<1|1); pushup(p); }//替换 inline SegmentTree ask(int l,int r,int p) { if(l<=t[p].l&&r>=t[p].r) return t[p]; int mid=(t[p].l+t[p].r)>>1; SegmentTree val; if(r<=mid) val=ask(l,r,p<<1); if(l>mid) val=ask(l,r,p<<1|1); if(l<=mid&&r>mid) { SegmentTree a,b; a=ask(l,r,p<<1); b=ask(l,r,p<<1|1); val.lmax=max(a.lmax,a.sum+b.lmax); val.rmax=max(b.rmax,b.sum+a.rmax); val.maxn=max(b.maxn,max(a.maxn,a.rmax+b.lmax)); }//查询时,可能有三种情况:左,右,组合,故需返回多个值,此处返回结构体,同时维护查询的值 return val; } int main() { scanf("%d %d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&hxt[i]); build(1,n,1); for(int i=1;i<=m;i++) { int k,x,y; scanf("%d %d %d",&k,&x,&y); if(k==1) { if(x>y) swap(x,y);//小细节 printf("%d\n",ask(x,y,1).maxn); } else { change(x,y,1); } } return 0; }
于是,此题就做出来了。
return 0;