一.原理分析
二.例题讲解
例题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