小白逛公园
解题思路
我们用线段树维护 m a x v , m a x l , m a x r , s maxv,maxl,maxr,s maxv,maxl,maxr,s 四个值,分别代表区间最大值,包含左端点在内的最大值,包括右端点内的最大值和区间总值。
显然,对于一个节点,它的转移方程如下:
now.s=l.s+r.s;
now.maxl=max(l.maxl,l.s+r.maxl);
now.maxr=max(r.maxr,r.s+l.maxr);
now.maxv=max(l.maxv,max(l.maxr+r.maxl,r.maxv));
code
#include<iostream>
#include<cstdio>
using namespace std;
int n,m;
struct abc{
int s;
int maxl,maxr,maxv;
}tree[2000010];
abc add(abc a,abc b)
{
abc c;
c.s=a.s+b.s;
c.maxl=max(a.maxl,a.s+b.maxl);
c.maxr=max(b.maxr,b.s+a.maxr);
c.maxv=max(a.maxv,max(a.maxr+b.maxl,b.maxv));
return c;
}
void down(abc &now,abc &l,abc &r)
{
if(l.maxr<0&&r.maxl<0)
now.maxv=max(l.maxr,r.maxl);
else
{
now.maxv=0;
if(l.maxr>0)
now.maxv+=l.maxr;
if(r.maxl>0)
now.maxv+=r.maxl;
}
now.maxv=max(now.maxv,l.maxv);
now.maxv=max(now.maxv,r.maxv);
now.maxl=max(l.maxl,l.s+r.maxl);
now.maxr=max(r.maxr,r.s+l.maxr);
now.s=l.s+r.s;
}
void build(int now,int x,int y)
{
if(x==y)
{
scanf("%d",&tree[now].s);
tree[now].maxl=tree[now].maxr=tree[now].maxv=tree[now].s;
return;
}
int mid=(x+y)/2;
build(now*2,x,mid);
build(now*2+1,mid+1,y);
down(tree[now],tree[now*2],tree[now*2+1]);
}
void change(int now,int x,int y,int p,int v)
{
if(x==y)
{
tree[now].s=tree[now].maxl=tree[now].maxr=tree[now].maxv=v;
return;
}
int mid=(x+y)/2;
if(p<=mid)
change(now*2,x,mid,p,v);
else
change(now*2+1,mid+1,y,p,v);
down(tree[now],tree[now*2],tree[now*2+1]);
}
abc fd(int now,int x,int y,int l,int r)
{
if(l<=x&&y<=r)
return tree[now];
int mid=(x+y)/2;
if(r<=mid)
return fd(now*2,x,mid,l,r);
if(l>mid)
return fd(now*2+1,mid+1,y,l,r);
abc a,b;
a=fd(now*2,x,mid,l,r);
b=fd(now*2+1,mid+1,y,l,r);
return add(a,b);
}
int main()
{
cin>>n>>m;
build(1,1,n);
while(m--)
{
int k,a,b;
scanf("%d%d%d",&k,&a,&b);
if(k==1)
{
if(a>b)
swap(a,b);
cout<<fd(1,1,n,a,b).maxv<<endl;
}
else
change(1,1,n,a,b);
}
}