Can you answer these queries III(线段树求区间最大子段和)

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(p2)+sum(p2+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(p2+1),sum(p2+1)+rmax(p2))
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(p2),lmax(p2+1)+sum(2p))
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(p2),max(dat(p2+1),lmax(p2+1)+rmax(p2)))

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;}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值