[线段树]校OJ-Can you answer on these queries III

这篇博客介绍了如何使用线段树解决在大规模数组中进行区间最大连续子段和查询及单点修改的问题。线段树通过维护每个节点的最大子段和、左端最大子段和和右端最大子段和,实现快速更新和查询。在建树和更新过程中,使用自底向上的方式更新节点信息。代码示例展示了线段树的实现细节,包括建树、单点修改和区间查询的函数。
摘要由CSDN通过智能技术生成

Can you answer on these queries III

题目简述

给定长度为N的数列A,以及M条指令 ( N ≤ 500000 , M ≤ 100000 ) (N≤500000, M≤100000) (N500000,M100000),每条指令可能是以下两种之一:

“2 x y”,把 A[x] 改成 y。

“1 x y”,查询区间 [x,y] 中的最大连续子段和,即区间 [ l , r ] [l,r] [l,r]内,连续累加和最大的。 对于每个询问,输出一个整数表示答案。

//input
5 3
1 2 -3 4 5
1 2 3
2 2 -1
1 3 2
//output
2
-1

思路
线段树的整体思路不变,我们只需在建树和单点修改时变化一下从下往上传递的信息即可,多维护三个信息,即连续最大子段和dat,左端的连续最大子段和lmax,以及右端的连续最大子段和rmax

t[bh].sum=t[bh*2].sum+t[bh*2+1].sum;
t[bh].lmax=max(t[bh*2].lmax,t[bh*2+1].lmax+t[2*bh].sum);
t[bh].rmax=max(t[bh*2+1].rmax,t[bh*2].rmax+t[2*bh+1].sum);
t[bh].dat=max(t[bh*2].dat,max(t[bh*2+1].dat,t[bh*2].rmax+t[bh*2+1].lmax));

PS:1.这里建议写一个更新函数update(int bh),每次更新值时调用次函数即可
2.线段树一般有多组输入输出,建议用快读或 s c a n f , p r i n t f scanf,printf scanf,printf

void update(int bh)
{
	t[bh].sum=t[bh*2].sum+t[bh*2+1].sum;
	t[bh].lmax=max(t[bh*2].lmax,t[bh*2+1].lmax+t[2*bh].sum);
	t[bh].rmax=max(t[bh*2+1].rmax,t[bh*2].rmax+t[2*bh+1].sum);
	t[bh].dat=max(t[bh*2].dat,max(t[bh*2+1].dat,t[bh*2].rmax+t[bh*2+1].lmax));
}

code

#include <bits/stdc++.h>
using namespace std;
const int MAXN=500086;
struct tree{
	int l,r,lmax,sum,rmax,dat;
}t[4*MAXN];
int n,a[MAXN],m;
void update(int bh)
{
	t[bh].sum=t[bh*2].sum+t[bh*2+1].sum;
	t[bh].lmax=max(t[bh*2].lmax,t[bh*2+1].lmax+t[2*bh].sum);
	t[bh].rmax=max(t[bh*2+1].rmax,t[bh*2].rmax+t[2*bh+1].sum);
	t[bh].dat=max(t[bh*2].dat,max(t[bh*2+1].dat,t[bh*2].rmax+t[bh*2+1].lmax));
} 
void build(int bh,int l,int r)
{
	t[bh].l=l;	
	t[bh].r=r;	
	if(l==r)
	{
		t[bh].sum=a[l];
		t[bh].dat=a[l];
		t[bh].lmax=a[l];
		t[bh].rmax=a[l];
		return ;
	}
	int mid=(l+r)/2;
	build(2*bh,l,mid);
	build(2*bh+1,mid+1,r);
	update(bh);
}
void change(int bh,int x,int summ)
{
	
	if(t[bh].l==t[bh].r)
	{
		t[bh].sum=summ;
		t[bh].dat=summ;
		t[bh].lmax=summ;
		t[bh].rmax=summ;
		return ;
	}
	int mid=(t[bh].l+t[bh].r)/2;
	if(x<=mid) change(bh*2,x,summ);
	else change(bh*2+1,x,summ);
	update(bh);
}
tree ask(int bh,int l,int r)
{
	if(l<=t[bh].l&&r>=t[bh].r)
	{
		return t[bh];
	}
	int mid=(t[bh].l+t[bh].r)/2;
	int w=-MAXN*10;
	if(mid>=r) return ask(bh*2,l,r);
	if(mid<l) return ask(bh*2+1,l,r);
	else {
		tree ans,left,right;
        left=ask(bh*2,l,r);
        right=ask(bh*2+1,l,r);
        ans.sum=left.sum+right.sum;
        ans.dat=max(max(left.dat,left.rmax+right.lmax),right.dat);
        ans.lmax=max(left.lmax,left.sum+right.lmax);
        ans.rmax=max(right.rmax,right.sum+left.rmax);
        return ans;
	}
}
int main()
{
	freopen("b.in","r",stdin);
	freopen("b.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
	}
	build(1,1,n);
	int a,b,c;
	while(m--)
	{
		scanf("%d%d%d",&a,&b,&c);
		if(a==2) change(1,b,c);
		else 
		{
			if(b>c) swap(b,c);
			printf("%d\n",ask(1,b,c).dat);	
		}
	}
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值