线段树维护最大字段和详解
简述
线段树可以维护区间信息,区间和,区间最大最小或区间gcd等,通过区间的维护我们还可以在O()的时间求出一个区间的最大子段和。
做法
首先我们线段树维护的节点变成结构体维护四个值,s为区间的和,ls为从左端点开始的最大字段和,rs为右端点开始的最大字段和,ms为区间的最大字段和。
struct node{ ll ls,rs,ms,s; }a[maxn<<2];
如何向上更新
我们发现对于一个节点的ms,若已经知道了它的左右子树的信息。
它的ms一定等于左子树的ms或右子树的ms或两个都取一点。
它的ls要么取左子树的ls,要么取左子树的全部加右子树的ls。
它的rs要么取右子树的rs,要么取右子树的全部加左子树的rs。
它的s就是标准的线段树两子数相加。
void pushup(int rt){ int lson=rt<<1; int rson=rt<<1|1; a[rt].s=a[lson].s+a[rson].s; a[rt].ls=max(a[lson].ls , a[lson].s+a[rson].ls); a[rt].rs=max(a[rson].rs , a[rson].s+a[lson].rs); a[rt].ms=max(max(a[lson].ms,a[rson].ms),a[lson].rs+a[rson].ls); }
单点更新
操作和标准线段树类似就不多说了。
void update(int pos,ll val,int l,int r,int rt){ //pos位置加val if(l==r){ ll tmp=a[rt].ms+val; a[rt].ls=a[rt].rs=a[rt].s=a[rt].ms=tmp; return; } int m=l+r>>1; if(pos<=m) update(pos,val,l,m,rt<<1); else update(pos,val,m+1,r,rt<<1|1); pushup(rt); }
区间查询 (查询区间最大字段和)
node query(int L,int R,int l,int r,int rt){ //返回代表查询区间信息的节点 if(L<=l&&r<=R){ return a[rt]; } int m=l+r>>1; node f1,f2,ans; if(R<=m) ans=query(L,R,l,m,rt<<1); if(L>m) ans=query(L,R,m+1,r,rt<<1|1); if(L<=m&&R>m){ f1=query(L,R,l,m,rt<<1); f2=query(L,R,m+1,r,rt<<1|1); ans.s=f1.s+f2.s; ans.ls=max(f1.ls,f1.s+f2.ls); ans.rs=max(f2.rs,f2.s+f1.rs); ans.ms=max(max(f1.ms,f2.ms),f1.rs+f2.ls); } return ans; }
时间复杂度
对于单点更新和区间查询,时间复杂度都是logn,递归过程和标志线段树是类似的。
模板
#include<iostream> #include<algorithm> using namespace std; const int maxn=; typedef long long ll; ll A[maxn]; struct node{ ll ls,rs,ms,s; }a[maxn<<2]; void pushup(int rt){ int lson=rt<<1; int rson=rt<<1|1; a[rt].s=a[lson].s+a[rson].s; a[rt].ls=max(a[lson].ls , a[lson].s+a[rson].ls); a[rt].rs=max(a[rson].rs , a[rson].s+a[lson].rs); a[rt].ms=max(max(a[lson].ms,a[rson].ms),a[lson].rs+a[rson].ls); } void build(int l,int r,int rt){ if(l==r){ a[rt].ls=a[rt].rs=a[rt].ms=a[rt].s=A[l]; return; } int m=l+r>>1; build(l,m,rt<<1); build(m+1,r,rt<<1|1); pushup(rt); } void update(int pos,ll val,int l,int r,int rt){ //pos位置加val if(l==r){ ll tmp=a[rt].ms+val; a[rt].ls=a[rt].rs=a[rt].s=a[rt].ms=tmp; return; } int m=l+r>>1; if(pos<=m) update(pos,val,l,m,rt<<1); else update(pos,val,m+1,r,rt<<1|1); pushup(rt); } node query(int L,int R,int l,int r,int rt){ //返回代表查询区间信息的节点 if(L<=l&&r<=R){ return a[rt]; } int m=l+r>>1; node f1,f2,ans; if(R<=m) ans=query(L,R,l,m,rt<<1); if(L>m) ans=query(L,R,m+1,r,rt<<1|1); if(L<=m&&R>m){ f1=query(L,R,l,m,rt<<1); f2=query(L,R,m+1,r,rt<<1|1); ans.s=f1.s+f2.s; ans.ls=max(f1.ls,f1.s+f2.ls); ans.rs=max(f2.rs,f2.s+f1.rs); ans.ms=max(max(f1.ms,f2.ms),f1.rs+f2.ls); } return ans; } int main() { return 0; }
一点一点积累,一点一点蜕变!