题
给定一个长度为
的序列
,以及
次询问,每次询问给定
两参数。
对于每次询问,求
到
之间的最大子段和,子段的意思是连续非空子区间。
更形式化地解释:对于每次询问给定的
,
求一个整数
,使得存在整数
,满足
且
。
其中,
,
在
范围内但不保证答案在
范围内。
解
看题就知道要数据结构啦,
我们直接考虑合并,对于某个区间,它的两个左右儿子区间怎样合并为这个区间?
首先对于每个节点,我们肯定要记录这个区间的最大子段和,记作
。但是如果直接把两个儿子的最大子段和取最大一定是错的,因为一个区间的最大子段可能会跨过左右区间的分界点,而不是单独分布在左区间或者右区间。
为了维护这种情况,我们得多记两个信息:
以该区间左/右端点为起点的最大子段和,分别记作
。
如果能够维护,那么上述的另一种情况就也能被我们维护下来。我们只要把左区间的
加上右区间的
,就能得出跨分界点的最大子段和。
但我们在合并时要怎样维护
和
呢?由于两个信息是对称的,我们拿
为例。
大区间的
一定等于左区间的
吗?不一定。因为可能跨过分界点。
如果跨过分界点,其就是左区间的所有元素和加上右区间的
。所以我们还得在维护一个区间和,这个非常好维护。
因此这就是合并了,放个代码:
void Merge(R node &fa,R node &s1,R node &s2)
{
fa.gss=max(max(s1.gss,s2.gss),s1.rgss+s2.lgss);
fa.lgss=max(s1.lgss,s1.sum+s2.lgss);
fa.rgss=max(s2.rgss,s2.sum+s1.rgss);
fa.sum=s1.sum+s2.sum;
}
(区间
与
合并为
。)
理一理思路:
- 每个节点记录以下四个信息: 。意义见上。
- 的维护
- 情况一:该区间的最大子段完全落在左子区间或右子区间。 。
- 情况二·:该区间的最大子段跨过左右区间分界点。 。
- 的维护( 同理)
- 情况一:该区间的 对应的子段完全落在左子区间。 。
- 情况二:该区间的 对应子段跨过分界点。 。
- 的维护: 。
合并弄清楚了其它都不难。询问就把询问区间拆成线段树上的区间然后逐个合并即可。复杂度
。
完整代码:
#include <bits/stdc++.h>
using namespace std;
#define R register
#define Maxn 200005
#define LL long long
#define lson (now<<1)
#define rson (lson|1)
#define inf -9999999999999999
int n,q;
struct node
{
LL gss,lgss,rgss,sum;
node(){gss=lgss=rgss=sum=inf;return;}
}T[Maxn<<2];
void Merge(R node &fa,R node &s1,R node &s2)
{
fa.gss=max(max(s1.gss,s2.gss),s1.rgss+s2.lgss);
fa.lgss=max(s1.lgss,s1.sum+s2.lgss);
fa.rgss=max(s2.rgss,s2.sum+s1.rgss);
fa.sum=s1.sum+s2.sum;
}
void Build(R int now,R int l,R int r)
{
if(l==r)
{
scanf("%lld",&T[now].gss);
T[now].lgss=T[now].rgss=T[now].sum=T[now].gss;
return ;
}
R int mid=(l+r)>>1;
Build(lson,l,mid);Build(rson,mid+1,r);
Merge(T[now],T[lson],T[rson]);
}
int ql,qr;
bool key;
node ans;
void Query(R int now,R int l,R int r)
{
if(ql<=l && qr>=r)
{
if(key) Merge(ans,ans,T[now]);
else ans=T[now],key=1;
return;
}
R int mid=(l+r)>>1;
if(mid >= ql)Query(lson,l,mid);
if(mid < qr)Query(rson,mid+1,r);
}
int main()
{
scanf("%d",&n);
Build(1,1,n);
scanf("%d",&q);
for (R int i=1;i<=q;++i)
{
scanf("%d %d",&ql,&qr);
key=0;Query(1,1,n);
printf("%lld\n",ans.gss);
}
return 0;
}