SP1043 GSS1 - Can you answer these queries I(线段树,区间最大子段和(静态))
Posted ztz11
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SP1043 GSS1 - Can you answer these queries I(线段树,区间最大子段和(静态))相关的知识,希望对你有一定的参考价值。
题目描述
给出了序列A[1],A[2],…,A[N]。 (a[i]≤15007,1≤N≤50000)。查询定义如下: 查询(x,y)=max{a[i]+a[i+1]+...+a[j];x≤i≤j≤y}。 给定M个查询,程序必须输出这些查询的结果。
输入输出格式
输入格式:
- 输入文件的第一行包含整数N。
- 在第二行,N个数字跟随。
- 第三行包含整数M。
- M行跟在后面,其中第1行包含两个数字xi和yi。
输出格式:
您的程序应该输出M查询的结果,每一行一个查询。
思路:
我们做这道题首先应该想的,是两个区间如何合并
很显然,合并后最大子段和,要么是原来左儿子的,要么是原来右儿子的
还有一种可能是左右两个儿子合并后在中间新生成的
所以,每个节点维护四个元素
分别表示他所管辖的区间和,他所管辖的区间中的最大连续子段和
从左起最大连续子段和(意思是子段的左端点一定是区间的左端点)
从右起最大连续子段和(意思同上)
此时我们可以这样转移:
sum(和)就不用说了
这一层的从左起最大连续子段和=max(左儿子的从左起最大连续子段和,左儿子的和+右儿子的从左起最大连续子段和)
这一层的从左起最大连续子段和方法同上
这一层的最大连续子段和=max(左儿子的最大连续子段和,右儿子的最大连续子段和,(左儿子从右起的最大连续字段和+右儿子从左起的最大连续子段和(也就是合并后生成的中间最大子段)))
OK,任务完成
查询同理
代码:
//这里我将建树当成更改节点值 #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define rii register int i #define rij register int j #define inf 1073741824 #define rs 65536 using namespace std; struct nod{ int lm,rm,maxn,sum; }x[6000005]; int n,q,cz,x1,y1; void add(int wz,int l,int r,int val,int bh) { if(l==r&&l==wz) { x[bh].maxn=val; x[bh].lm=val; x[bh].rm=val; x[bh].sum=val; return; } int ltt=(l+r)/2; if(wz<=ltt) { add(wz,l,ltt,val,bh*2); } else { add(wz,ltt+1,r,val,bh*2+1); } x[bh].sum=x[bh*2].sum+x[bh*2+1].sum; x[bh].lm=max(x[bh*2].lm,x[bh*2].sum+x[bh*2+1].lm); x[bh].rm=max(x[bh*2+1].rm,x[bh*2+1].sum+x[bh*2].rm); x[bh].maxn=max(x[bh*2].maxn,max(x[bh*2+1].maxn,x[bh*2].rm+x[bh*2+1].lm)); } nod query(int l,int r,int nl,int nr,int bh) { nod an,bn; if(l<nl) { l=nl; } if(r>nr) { r=nr; } if(nl==l&&nr==r) { an=x[bh]; return an; } int ltt=(nl+nr)/2; if(l<=ltt&&r<=ltt) { return an=query(l,r,nl,ltt,bh*2); } if(r>ltt&&l>ltt) { return bn=query(l,r,ltt+1,nr,bh*2+1); } else { an=query(l,r,nl,ltt,bh*2); bn=query(l,r,ltt+1,nr,bh*2+1); an.maxn=max(an.maxn,max(bn.maxn,an.rm+bn.lm)); an.lm=max(an.lm,an.sum+bn.lm); an.rm=max(bn.rm,bn.sum+an.rm); an.sum=an.sum+bn.sum; return an; } } int main() { // freopen("brs.in","r",stdin); // freopen("brs.out","w",stdout); for(rii=1;i<=150005;i++) { x[i].lm=-inf; x[i].rm=-inf; x[i].maxn=-inf; } scanf("%d",&n); for(rii=1;i<=n;i++) { int ltt; scanf("%d",<t); add(i,1,rs,ltt,1); } scanf("%d",&q); for(rii=1;i<=q;i++) { scanf("%d%d",&x1,&y1); nod ans=query(x1,y1,1,rs,1); printf("%d ",ans.maxn); } }
以上是关于SP1043 GSS1 - Can you answer these queries I(线段树,区间最大子段和(静态))的主要内容,如果未能解决你的问题,请参考以下文章
luogu SP1043 GSS1 - Can you answer these queries I
luogu SP1043 GSS1 - Can you answer these queries I
SP1043GSS1 - Can you answer these queries I
「SP1043」GSS1 - Can you answer these queries I