[线段树] P4513 小白逛公园
题意:
序列,单点修改,询问区间最大子段和
最大子段和指的是找出一个可以是空的子区间,和最大
著名的新手杀手题。。。
其实也不难
对于每个区间,维护一个最大前缀,最大后缀,以及区间内部的答案
每次合并的时候,即答案选取左子区间的max,右子区间的max,或者左子区间的最大后缀+右子区间的最大前缀
\(\\\)
\(\\\)
\(\\\)
\(\\\)
\(\\\)
#include<bits/stdc++.h>
#define int long long
#define mid ((s+t)>>1)
#define ls (p<<1)
#define rs (ls+1)
using namespace std;
const int Max=5e5+10;
int n,m;
int a[Max];
struct node
{
int res,sum,lm,rm;
}d[Max*4];
void pushup(int p)
{
d[p].sum=d[ls].sum+d[rs].sum;
d[p].res=max(d[ls].rm+d[rs].lm,max(d[rs].res,d[ls].res));
if(d[rs].lm>d[ls].lm-d[ls].sum) d[p].lm=d[ls].sum+d[rs].lm;
else d[p].lm=d[ls].lm;
if(d[ls].rm>d[rs].rm-d[rs].sum) d[p].rm=d[rs].sum+d[ls].rm;
else d[p].rm=d[rs].rm;
}
void build(int p,int s,int t)
{
if(s==t)
{
d[p].sum=a[s];
d[p].lm=a[s];
d[p].rm=a[s];
d[p].res=a[s];
return;
}
build(ls,s,mid);
build(rs,mid+1,t);
pushup(p);
}
void update(int p,int s,int t,int x,int c)
{
if(s==t)
{
d[p].sum=c;
d[p].res=c;
d[p].lm=c;
d[p].rm=c;
return;
}
if(x<=mid) update(ls,s,mid,x,c);
else update(rs,mid+1,t,x,c);
pushup(p);
}
node query(int p,int l,int r,int s,int t)
{
if(l<=s&&r>=t)
{
return d[p];
}
if(r<=mid) return query(ls,l,r,s,mid);
else if(l>mid) return query(rs,l,r,mid+1,t);
else
{
auto x=query(ls,l,r,s,mid),y=query(rs,l,r,mid+1,t);
node ans;
ans.sum=x.sum+y.sum;
ans.res=max(x.rm+y.lm,max(x.res,y.res));
if(y.lm>x.lm-x.sum) ans.lm=x.sum+y.lm;
else ans.lm=x.lm;
if(x.rm>y.rm-y.sum) ans.rm=y.sum+x.rm;
else ans.rm=y.rm;
return ans;
}
}
signed main()
{
ios::sync_with_stdio(0);
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
build(1,1,n);
for(int i=1;i<=m;i++)
{
int x,y,z;
cin>>x>>y>>z;
if(x==1)
{
if(z<y) swap(z,y);
cout<<query(1,y,z,1,n).res<<"\n";
}
else
{
update(1,1,n,y,z);
}
}
return 0;
}