求解最大子段和可以通过dp的方式,如果涉及修改操作,在修改后再进行dp爆time,通过线段树log级的时间复杂度可在修改后快速得到答案
大致思路:
节点表示区间的最大和,该最大和由左子节点的最大和、右子节点的最大和以及左子节点的最大后缀和+右子节点的最大前缀和更新。说下为什么不直接用后缀和+前缀和更新:往下走有的节点的最大值是不加上右节点的,那么这个时候不能形成连续的段,因此最大和应该补上后缀+前缀
区间的最大前缀由左子节点的最大前缀或者左子节点和+右子节点前缀更新
区间的最大后缀由右子节点的最大后缀或者右子节点和+左子节点后缀更新
道理也很明显
struct team {
int l,r;
ll v,sum,lmax,rmax,maxx;
}a[4*N];
void push(int root) {
a[root].sum=a[root<<1].sum+a[root<<1|1].sum;
a[root].lmax=max(a[root<<1].lmax,a[root<<1].sum+a[root<<1|1].lmax);
a[root].rmax=max(a[root<<1|1].rmax,a[root<<1|1].sum+a[root<<1].rmax);
a[root].maxx=max(a[root<<1].maxx,max(a[root<<1|1].maxx,a[root<<1].rmax+a[root<<1|1].lmax));
}
void buildtree(int l,int r,int root) {
a[root].l=l,a[root].r=r;
if(l==r) {
cin>>a[root].v;
a[root].sum=a[root].v;
a[root].lmax=a[root].v;
a[root].rmax=a[root].v;
a[root].maxx=a[root].v;
return ;
}
int mid=l+(r-l)/2;
buildtree(l,mid,root<<1);
buildtree(mid+1,r,root<<1|1);
push(root);
}
void update(int pos,int x,int root) {
int L=a[root].l,R=a[root].r;
if(L==R) {
a[root].v=x;
a[root].sum=x;
a[root].lmax=x;
a[root].rmax=x;
a[root].maxx=x;
return ;
}
int mid=L+(R-L)/2;
if(pos<=mid) update(pos,x,root<<1);
else update(pos,x,root<<1|1);
push(root);
}
team query(int l,int r,int root) {
team t=a[root];
int L=a[root].l,R=a[root].r;
int mid=L+(R-L)/2;
if(l<=L&&R<=r) return t;
if(r<=mid) return query(l,r,root<<1);
if(l>mid) return query(l,r,root<<1|1);
if(l<=mid&&r>mid) {
team ans1=query(l,r,root<<1),ans2=query(l,r,root<<1|1);
t.sum=ans1.sum+ans2.sum;
t.lmax=max(ans1.lmax,ans1.sum+ans2.lmax);
t.rmax=max(ans2.rmax,ans2.sum+ans1.rmax);
t.maxx=max(ans1.maxx,max(ans2.maxx,ans1.rmax+ans2.lmax));
return t;
}
}