最大子段和

求解最大子段和可以通过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;
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值