GSS 1 区间最大子段和
刚学线段树,在codevs上做完线段树练习1-3,然后高二神犇LTY给我看了这个GSS系列,今天下午终于做完了。之前好多题都没往博客上写,之后到寒假会慢慢补。
这个题有m次询问,(没给m的范围…)这样DP会TLE吧,所以用线段树来做。用线段树维护4个值,这一段的总和sum,这一段的最大子段和mx,从这段的左端开始 最大值lm,从这段右端开始的最大值rm。然后按照上面的方式建树每个点从他的左右儿子转移而来。 之后就是查询,用ans表示答案(最终的答案),rans表示 当前节点之后 向右去转移的值。rans=max(tree[pos].rm,rans+tree[pos].sum);这样就完成了查找,然后是代码
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
int st,ed,ans,rans;
struct sgetree
{
int sum,mx,lm,rm;
}tree[210000];
void build(int l,int r,int pos)
{
if(l==r)
{
scanf("%d",&tree[pos].sum);
tree[pos].lm=tree[pos].sum;
tree[pos].rm=tree[pos].sum;
tree[pos].mx=tree[pos].sum;
return;
}
int mid=(l+r)/2,lson=pos*2,rson=pos*2+1;
build(l,mid,lson);
build(mid+1,r,rson);
tree[pos].sum=tree[lson].sum+tree[rson].sum;
tree[pos].lm=max(tree[lson].lm,tree[lson].sum+tree[rson].lm);
tree[pos].rm=max(tree[rson].rm,tree[rson].sum+tree[lson].rm);
tree[pos].mx=max(max(tree[rson].mx,tree[lson].mx),tree[lson].rm+tree[rson].lm);
return;
}
void find(int l,int r,int pos)
{
if(st<=l&&r<=ed)
{
ans=max(ans,max(tree[pos].mx,rans+tree[pos].lm));
rans=max(tree[pos].rm,rans+tree[pos].sum);
return;
}
int mid=(l+r)/2,lson=pos*2,rson=pos*2+1;
if(st<=mid)
{
find(l,mid,lson);
}
if(mid<ed)
{
find(mid+1,r,rson);
}
return;
}
int main()
{
int n,m,i;
scanf("%d",&n);
build(1,n,1);
scanf("%d",&m);
for(i=1;i<=m;i++)
{
scanf("%d%d",&st,&ed);
ans=-200000000;
rans=-200000000;
find(1,n,1);
printf("%d\n",ans);
}
return 0;
}