算是线段树里面很裸的一类题了,但是考场上忘记了怎么写qwq。
考试的题是环上的,补题的时候发现很熟悉,就想起来这一类模型之前刚学线段树老师讲过呀qwq(没有认真听讲),但是之前的板子已经被埋没在学校的老oj里面了,就还是重新写了一个模板:
小白逛公园
首先,线段树要维护这样四个域:
sum:该区间的和
max:该区间上的最大子段和
maxl:为必须包含左端点的最大子段和(相当于最大前缀)
maxr:为必须包含右端点的最大子段和(相当于最大后缀)
maxl和maxr的使用使得更新非常地方便,详情见下:
修改时:
1、max:左右儿子的max,左儿子的maxr+右儿子的maxl,取最大值。
2、maxl:左儿子的maxl与左儿子sum和右儿子maxl和的最大值。
3、maxr:右儿子的maxr与右儿子sum和左儿子maxr和的最大值。
4、sum:左右儿子sum之和。
查询时:
1、如果查询区间覆盖这一节点,将该节点信息返回。
2、如果只与一个儿子有交集,就返回在那个儿子中查找到的信息。
3、如果与两个儿子都有交集,就先分别计算出两个儿子的信息,然后按修改的方式将两个信息合并,然后返回。
4、最后返回的值即为答案。
代码:
//带修最大子段和模板
#include
#include
#include
#include
#include
#include
using namespace std;
#define N 500005
#define ll long long
#define INF 0x3f3f3f3f
struct node{
int l,r;
int sum,ms/*maxsum*/,ml,mr/*maxl,maxr*/;
}tree[N*4];
int n,m,a[N];
inline int rd()
{
int f=1,x=0;char c=getchar();
while(c<'0'||'9'<c){if(c=='-')f=-1;c=getchar();}
while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return f*x;
}
//-----
void PushUp(int i)
{
tree[i].sum=tree[i<<1].sum+tree[i<<1|1].sum;
tree[i].ml=max(tree[i<<1].sum+tree[i<<1|1].ml,tree[i<<1].ml);
tree[i].mr=max(tree[i<<1|1].sum+tree[i<<1].mr,tree[i<<1|1].mr);
tree[i].ms=max(max(tree[i<<1].ms,tree[i<<1|1].ms),tree[i<<1].mr+tree[i<<1|1].ml);
}
void build(int i,int l,int r)
{
tree[i].l=l,tree[i].r=r;
if(l==r)
{
tree[i].sum=tree[i].ml=tree[i].mr=tree[i].ms=a[l];
return ;
}
int mid=(l+r)>>1;
build(i<<1,l,mid);
build(i<<1|1,mid+1,r);
PushUp(i);
}
void update(int i,int pos,int val)
{
if(tree[i].l==tree[i].r)
{
tree[i].ms=tree[i].ml=tree[i].mr=tree[i].sum=val;
return ;
}
int mid=(tree[i].l+tree[i].r)>>1;
if(pos<=mid)
update(i<<1,pos,val);
else update(i<<1|1,pos,val);
PushUp(i);
}
node query(int i,int l,int r)
{
if(l<=tree[i].l&&tree[i].r<=r)
return tree[i];
int mid=(tree[i].l+tree[i].r)>>1;
if(r<=mid) return query(i<<1,l,r);
else if(l>mid) return query(i<<1|1,l,r);
else
{
node x=query(i<<1,l,r),y=query(i<<1|1,l,r),res;
//合并答案
res.sum=x.sum+y.sum;
res.ml=max(x.sum+y.ml,x.ml);
res.mr=max(y.sum+x.mr,y.mr);
res.ms=max(max(x.ms,y.ms),x.mr+y.ml);
return res;
}
}
//-----
int main()
{
n=rd(),m=rd();
for(int i=1;i<=n;i++)
a[i]=rd();
build(1,1,n);
while(m--)
{
int opt=rd();
if(opt==1)
{
int x=rd(),y=rd(),tmp;
if(x>y) tmp=x,x=y,y=tmp;
printf("%d\n",query(1,x,y).ms);
}
else if(opt==2)
{
int x=rd(),y=rd();
update(1,x,y);
}
}
return 0;
}
下面这种实现是在结构体里面去掉了l和r,带到函数里面去, 据说 可以省空间。
//带修最大子段和模板
#include
#include
#include
#include
#include
#include
using namespace std;
#define N 500005
#define ll long long
#define INF 0x3f3f3f3f
struct node{
int sum,ms/*maxsum*/,ml,mr/*maxl,maxr*/;
}tree[N*4];
int n,m,a[N];
inline int rd()
{
int f=1,x=0;char c=getchar();
while(c<'0'||'9'<c){if(c=='-')f=-1;c=getchar();}
while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return f*x;
}
//-----
void PushUp(int i)
{
tree[i].sum=tree[i<<1].sum+tree[i<<1|1].sum;
tree[i].ml=max(tree[i<<1].sum+tree[i<<1|1].ml,tree[i<<1].ml);
tree[i].mr=max(tree[i<<1|1].sum+tree[i<<1].mr,tree[i<<1|1].mr);
tree[i].ms=max(max(tree[i<<1].ms,tree[i<<1|1].ms),tree[i<<1].mr+tree[i<<1|1].ml);
}
void build(int i,int l,int r)
{
if(l==r)
{
tree[i].sum=tree[i].ml=tree[i].mr=tree[i].ms=a[l];
return ;
}
int mid=(l+r)>>1;
build(i<<1,l,mid);
build(i<<1|1,mid+1,r);
PushUp(i);
}
void update(int i,int pos,int val,int l,int r)
{
if(l==r)
{
tree[i].ms=tree[i].ml=tree[i].mr=tree[i].sum=val;
return ;
}
int mid=(l+r)>>1;
if(pos<=mid)
update(i<<1,pos,val,l,mid);
else update(i<<1|1,pos,val,mid+1,r);
PushUp(i);
}
node query(int i,int li,int ri,int l,int r)
{
if(l<=li&&ri<=r)
return tree[i];
int mid=(li+ri)>>1;
if(r<=mid) return query(i<<1,li,mid,l,r);
else if(l>mid) return query(i<<1|1,mid+1,ri,l,r);
else
{
node x=query(i<<1,li,mid,l,r),y=query(i<<1|1,mid+1,ri,l,r),res;
//合并答案
res.sum=x.sum+y.sum;
res.ml=max(x.sum+y.ml,x.ml);
res.mr=max(y.sum+x.mr,y.mr);
res.ms=max(max(x.ms,y.ms),x.mr+y.ml);
return res;
}
}
//-----
int main()
{
n=rd(),m=rd();
for(int i=1;i<=n;i++)
a[i]=rd();
build(1,1,n);
while(m--)
{
int opt=rd();
if(opt==1)
{
int x=rd(),y=rd(),tmp;
if(x>y) tmp=x,x=y,y=tmp;
printf("%d\n",query(1,1,n,x,y).ms);
}
else if(opt==2)
{
int x=rd(),y=rd();
update(1,x,y,1,n);
}
}
return 0;
}