BZOJ-1756 Vijos1083 小白逛公园(线段树维护最大子段和)
题目描述
给定长为 \(n(1\leq n\leq 5\times 10^5)\) 的序列 \(a\),以及 \(m(1\leq m\leq 10^5)\) 次操作,有两种操作:
操作 \(1\): 1 l r,查询区间 \([l,r]\) 中的最大连续子段和,即 \(\max\limits_{l\leq x\leq y\leq r}\Big\{\displaystyle\sum_{i=x}^{y}a[i]\Big\}\)。
操作 \(2\):2 x v,把 \(a[x]\) 修改成 \(v\)。
对于每个操作 \(1\),输出一个整数表示答案。
分析
在线段树的每个节点中除了区间左右端点外再维护 \(4\) 个信息:区间和 \(sum\),区间最大连续子段和 \(dat\),紧靠左端的最大连续子段和 \(lmax\),紧靠右端的最大连续子段和 \(rmax\)。
在 \(build\) 和 \(update\) 函数中从下往上传递信息:
tree[p].sum=tree[p*2].sum+tree[p*2+1].sum;
tree[p].lmax=max(tree[p*2].lmax,tree[p*2].sum+tree[p*2+1].lmax);
tree[p].rmax=max(tree[p*2+1].rmax,tree[p*2+1].sum+tree[p*2].rmax);
tree[p].dat=max(tree[p*2].dat,tree[p*2+1].dat,tree[p*2].lmax+tree[p*2+1].rmax);
在询问最大连续子段和时需要通过合并区间来更新答案,因为最大连续子段和的区间可能不是线段树的一个节点(即无法通过查找左右儿子访问),所以函数返回类型是结构体的节点而不是值。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
int n,m,a[N];
struct SegmentTree
{
int l,r;
int sum,dat;
int lmax,rmax;
}tree[N<<2];
void pushup(int p)
{
tree[p].sum=tree[p*2].sum+tree[p*2+1].sum;
tree[p].lmax=max(tree[p*2].lmax,tree[p*2].sum+tree[p*2+1].lmax);
tree[p].rmax=max(tree[p*2+1].rmax,tree[p*2+1].sum+tree[p*2].rmax);
tree[p].dat=max(max(tree[p*2].dat,tree[p*2+1].dat),tree[p*2].rmax+tree[p*2+1].lmax);
}
void build(int p,int l,int r)
{
tree[p].l=l;tree[p].r=r;
if(l==r)
{
tree[p].dat=a[l];
tree[p].sum=a[l];
tree[p].lmax=a[l];
tree[p].rmax=a[l];
return ;
}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
pushup(p);
}
void update(int p,int x,int val)
{
if(tree[p].l==tree[p].r)
{
tree[p].sum=val;
tree[p].lmax=val;
tree[p].rmax=val;
tree[p].dat=val;
return ;
}
int mid=(tree[p].l+tree[p].r)/2;
if(x<=mid)
update(p*2,x,val);
else
update(p*2+1,x,val);
pushup(p);
}
SegmentTree query(int p,int l,int r)
{
if(l<=tree[p].l&&tree[p].r<=r)
return tree[p];
int mid=(tree[p].l+tree[p].r)/2;
if(r<=mid)
return query(p*2,l,r);
if(l>mid)
return query(p*2+1,l,r);
SegmentTree a,b,ans;
a=query(p*2,l,r);b=query(p*2+1,l,r);
ans.sum=a.sum+b.sum;
ans.lmax=max(a.lmax,a.sum+b.lmax);
ans.rmax=max(b.rmax,a.rmax+b.sum);
ans.dat=max(max(a.dat,b.dat),a.rmax+b.lmax);
return ans;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
build(1,1,n);
while(m--)
{
int op;
scanf("%d",&op);
if(op==2)
{
int x,v;
scanf("%d %d",&x,&v);
update(1,x,v);
}
if(op==1)
{
int l,r;
scanf("%d %d",&l,&r);
if(l>r)
swap(l,r);
printf("%d\n",query(1,l,r).dat);
}
}
return 0;
}
posted on 2020-11-25 15:38 DestinHistoire 阅读(66) 评论(0) 收藏 举报
浙公网安备 33010602011771号