Can you answer these queries III(区间最大子段和)
蓝书题目Can you answer these queries III
给定长度为N的数列A,以及M条指令 (N≤500000, M≤100000),每条指令可能是以下两种之一:
- “2 x y”,把 A[x] 改成 y。
- “1 x y”,查询区间 [x,y] 中的最大连续子段和,即max(x≤l≤r≤y)∑ri=lA[i]。
对于每个询问,输出一个整数表示答案。
思路:
在线段树除去区间端点外,在维护区间和
s
u
m
sum
sum,区间最大子段和
d
a
t
dat
dat,左端最大连续子段和
l
m
a
x
lmax
lmax,右端最大连续子段和
r
m
a
x
rmax
rmax
传递方程改变:
s
u
m
(
p
)
=
s
u
m
(
p
∗
2
)
+
s
u
m
(
p
∗
2
+
1
)
sum(p)=sum(p*2)+sum(p*2+1)
sum(p)=sum(p∗2)+sum(p∗2+1)
r
m
a
x
(
p
)
=
m
a
x
(
r
m
a
x
(
p
∗
2
+
1
)
,
s
u
m
(
p
∗
2
+
1
)
+
r
m
a
x
(
p
∗
2
)
)
rmax(p)=max(rmax(p*2+1),sum(p*2+1)+rmax(p*2))
rmax(p)=max(rmax(p∗2+1),sum(p∗2+1)+rmax(p∗2))
l
m
a
x
(
p
)
=
m
a
x
(
l
m
a
x
(
p
∗
2
)
,
l
m
a
x
(
p
∗
2
+
1
)
+
s
u
m
(
2
∗
p
)
)
lmax(p)=max(lmax(p*2),lmax(p*2+1)+sum(2*p))
lmax(p)=max(lmax(p∗2),lmax(p∗2+1)+sum(2∗p))
d
a
t
(
p
)
=
m
a
x
(
d
a
t
(
p
∗
2
)
,
m
a
x
(
d
a
t
(
p
∗
2
+
1
)
,
l
m
a
x
(
p
∗
2
+
1
)
+
r
m
a
x
(
p
∗
2
)
)
)
dat(p)=max(dat(p*2),max(dat(p*2+1),lmax(p*2+1)+rmax(p*2)))
dat(p)=max(dat(p∗2),max(dat(p∗2+1),lmax(p∗2+1)+rmax(p∗2)))
struct SegmentTree{
int l,r;
int dat,sum,lmax,rmax;
#define l(x) tree[x].l
#define r(x) tree[x].r
#define dat(x) tree[x].dat
#define sum(x) tree[x].sum
#define lmax(x) tree[x].lmax
#define rmax(x) tree[x].rmax
}tree[maxn*4];
int a[maxn];
int n,m;
void build(int p,int l,int r){
l(p)=l,r(p)=r;
if(l==r){
dat(p)=a[l];sum(p)=a[l];lmax(p)=a[l];rmax(p)=a[l];return;
}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
sum(p)=sum(p*2)+sum(p*2+1);
rmax(p)=max(rmax(p*2+1),sum(p*2+1)+rmax(p*2));
lmax(p)=max(lmax(p*2),lmax(p*2+1)+sum(2*p));
dat(p)=max(dat(p*2),max(dat(p*2+1),lmax(p*2+1)+rmax(p*2)));
}
void change(int p,int x,int z){
if(l(p)==r(p)){
dat(p)=z;sum(p)=z;lmax(p)=z;rmax(p)=z;return;
}
int mid=(l(p)+r(p))/2;
if(x<=mid) change(p*2,x,z);
else change(p*2+1,x,z);
sum(p)=sum(p*2)+sum(p*2+1);
rmax(p)=max(rmax(p*2+1),sum(p*2+1)+rmax(p*2));
lmax(p)=max(lmax(p*2),lmax(p*2+1)+sum(2*p));
dat(p)=max(dat(p*2),max(dat(p*2+1),lmax(p*2+1)+rmax(p*2)));
}
SegmentTree ask(int p,int l,int r){
if(l<=l(p)&&r>=r(p)) return tree[p];
SegmentTree a,b,ans;
a.sum=a.lmax=a.rmax=a.dat=b.sum=b.lmax=b.rmax=b.dat=-1*inf;
ans.sum=0;
int mid=(l(p)+r(p))/2;
if(l<=mid){a=ask(p*2,l,r);ans.sum+=a.sum;}
if(r>mid){b=ask(p*2+1,l,r);ans.sum+=b.sum;}
ans.dat=max(max(a.dat,b.dat),a.rmax+b.lmax);
ans.lmax=max(a.lmax,a.sum+b.lmax);
ans.rmax=max(b.rmax,b.sum+a.rmax);
if(l>mid)ans.lmax=max(ans.lmax,b.lmax);
if(r<=mid)ans.rmax=max(ans.rmax,a.rmax);
return ans;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
build(1,1,n);
while(m--){
int op,x,y;
cin>>op>>x>>y;
if(op==2){
change(1,x,y);
}
else {if(x>y)swap(x,y);cout<<ask(1,x,y).dat<<endl;}
}
}