线段树求最大连续子段和(详细讲解+例题分析)

线段树求最大连续子段和

一.原理分析

在这里插入图片描述
在这里插入图片描述

二.例题讲解

例题1:

https://vjudge.z180.cn/problem/SPOJ-GSS1

题目大意:
给你一个长度为N的序列,再给你M次询问,每一次询问给你一个x,y
要求输出区间[x,y]的最大连续子段的和是多少.

分析:这道理就是就是最大连续子段的板子题,搞懂上面的原理分析就可以轻松解决了

AC代码:

#include<bits/stdc++.h>
#define ls dep<<1
#define rs dep<<1|1
using namespace std;
const int Maxn = 5e4+10;
int f[Maxn*4];
int lmax[Maxn*4];
int a[Maxn];
int rmax[Maxn*4];
int sum[Maxn*4];
void pushup(int dep)
{
    
    
	sum[dep] = sum[ls]+sum[rs];
	f[dep] = max(max(f[ls],f[rs]),rmax[ls]+lmax[rs]);
	rmax[dep] = max(rmax[rs],sum[rs]+rmax[ls]);
	lmax[dep] = max(lmax[ls],sum[ls]+lmax[rs]);
	return ;
}
void build(int pos,int dep,int l,int r)
{
    
    
	if(l==r)
	{
    
    
		sum[dep] = a[l];
		f[dep] = a[l];
		lmax[dep] = a[l];
		rmax[dep] = a[l];
		return ;
	}
	int mid = l+r>>1;
	if(pos<=mid) build(pos,ls,l,mid);
	else build(pos,rs,mid+1,r);
	pushup(dep);
	return ;
}
void query(int ql,int qr,int dep,int l,int r,int &Sumx,int &Fx,int &Lmax,int &Rmax)
{
    
    
	if(ql<=l&&r<=qr)
	{
    
    
		Sumx = sum[dep];
		Fx = f[dep];
		Lmax = lmax[dep];
		Rmax = rmax[dep];
		return ;
	}
	int mid = l+r>>1;
	/*注意这里的lsumx和rsumx必须初始化为0,因为左或右儿子可能不会跟新到*/
	int lsumx=0,lfx=-1e9,lmaxl=-1e9,rmaxl=-1e9;
	int rsumx=0,rfx=-1e9,lmaxr=-1e9,rmaxr=-1e9;
	if(ql<=mid) query(ql,qr,ls,l,mid,lsumx,lfx,lmaxl,rmaxl); 
	if(qr>mid)  query(ql,qr,rs,mid+1,r,rsumx,rfx,lmaxr,rmaxr);
	Sumx = lsumx+rsumx;
	Rmax = max(rmaxr,rsumx+rmaxl);
	Lmax = max(lmaxl,lsumx+lmaxr);
	Fx = max(max(lfx,rfx),lmaxr+rmaxl);
	return ;
}
int main()
{
    
    
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
    
    
		cin>>a[i];
		build(i,1,1,n);
	}
	
	int m;
	cin>>m;
	for(int i=1;i<=m;i++)
	{
    
    
		int ql,qr;
		cin>>ql>>qr;
		int sum,f,lmax,rmax;
		query(ql,qr,1,1,n,sum,f,lmax,rmax);
		cout<<f<<'\n';
	}
	return 0;
}

例题2:

题目大意:这道题就是在例题1的基础上加了一个单点修改的操作,题目意思就不解释了,很好理解.

题目分析:这道题只是多了一个单点修改,既然我们有了pushup()函数跟新的操作,那么我们直接写一个单点修改的update函数即可.

AC代码:

#include<bits/stdc++.h>
#define ls dep<<1
#define rs dep<<1|1
using namespace std;
const int Maxn = 5e4+10;
int f[Maxn*4];
int lmax[Maxn*4];
int a[Maxn];
int rmax[Maxn*4];
int sum[Maxn*4];
void pushup(int dep)
{
    
    
	sum[dep] = sum[ls]+sum[rs];
	f[dep] = max(max(f[ls],f[rs]),rmax[ls]+lmax[rs]);
	rmax[dep] = max(rmax[rs],sum[rs]+rmax[ls]);
	lmax[dep] = max(lmax[ls],sum[ls]+lmax[rs]);
	return ;
}
/*单点修改*/
void update(int pos,int dep,int val,int l,int r)
{
    
    
	if(l==r)
	{
    
    
		sum[dep] = f[dep] = lmax[dep] = rmax[dep] = val;
		return ;
	}
	int mid = l+r>>1;
	if(pos<=mid) update(pos,ls,val,l,mid);
	else update(pos,rs,val,mid+1,r);
	pushup(dep);
	return ;
}
/*建立线段树*/
void build(int pos,int dep,int l,int r)
{
    
    
	if(l==r)
	{
    
    
		sum[dep] = a[l];
		f[dep] = a[l];
		lmax[dep] = a[l];
		rmax[dep] = a[l];
		return ;
	}
	int mid = l+r>>1;
	if(pos<=mid) build(pos,ls,l,mid);
	else build(pos,rs,mid+1,r);
	pushup(dep);
	return ;
}
/*区间查询*/
void query(int ql,int qr,int dep,int l,int r,int &Sumx,int &Fx,int &Lmax,int &Rmax)
{
    
    
	if(ql<=l&&r<=qr)
	{
    
    
		Sumx = sum[dep];
		Fx = f[dep];
		Lmax = lmax[dep];
		Rmax = rmax[dep];
		return ;
	}
	int mid = l+r>>1;
	/*注意这里的lsumx和rsumx必须初始化为0,因为左或右儿子可能不会跟新到*/
	int lsumx=0,lfx=-1e9,lmaxl=-1e9,rmaxl=-1e9;
	int rsumx=0,rfx=-1e9,lmaxr=-1e9,rmaxr=-1e9;
	if(ql<=mid) query(ql,qr,ls,l,mid,lsumx,lfx,lmaxl,rmaxl); 
	if(qr>mid)  query(ql,qr,rs,mid+1,r,rsumx,rfx,lmaxr,rmaxr);
	Sumx = lsumx+rsumx;
	Rmax = max(rmaxr,rsumx+rmaxl);
	Lmax = max(lmaxl,lsumx+lmaxr);
	Fx = max(max(lfx,rfx),lmaxr+rmaxl);
	return ;
}
int main()
{
    
    
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
    
    
		cin>>a[i];
		build(i,1,1,n);
	}
	
	int m;
	cin>>m;
	for(int i=1;i<=m;i++)
	{
    
    
		int op;
		int ql,qr;
		int pos,val; 
		cin>>op;
		if(op==1)
		{
    
    
			cin>>ql>>qr;
		int sum,f,lmax,rmax;
		query(ql,qr,1,1,n,sum,f,lmax,rmax);
		cout<<f<<'\n';
	    }
	    else
	    {
    
    
	    	cin>>pos>>val;
	    	update(pos,1,val,1,n);
		}
	}
	return 0;
}

如果还是不清楚的话,这里分享一篇视频讲解希望能帮助到你
视频链接:https://www.bilibili.com/video/BV1Tk4y1m7VM?p=16

猜你喜欢

转载自blog.csdn.net/TheWayForDream/article/details/116759814