spoj 2916. Can you answer these queries V(线段树)
2013-10-14 10:45
573 查看
题目链接:http://www.spoj.com/problems/GSS5/
题意:给出n个数,求区间最大子段和,但是限制了子段的起点终点,起点要在[x1,y1]内,终点要在[x2,y2]内。
思路:其实也不是很难,但是要分情况讨论,比较烦。首先,如果y1<x2,那么(y1,x2)这个区间内肯定要选择,那么就要个[x1,y1]的最大后缀和[x2,y2]的最大前缀就行了。如果x2<=y1,那么就要再分四种情况,一种起点终点都在[x2,y1]内;第二种起点在[x1,x2)内,终点在[x2,y1]内;第三种是起点在[x2,y1]内,终点在(y1,y2]内;最后一种是起点在[x1,x2)内,终点在(y1,y2]内。这些计算相应区间和还有最大前缀后缀就能算出来了。
代码:
题意:给出n个数,求区间最大子段和,但是限制了子段的起点终点,起点要在[x1,y1]内,终点要在[x2,y2]内。
思路:其实也不是很难,但是要分情况讨论,比较烦。首先,如果y1<x2,那么(y1,x2)这个区间内肯定要选择,那么就要个[x1,y1]的最大后缀和[x2,y2]的最大前缀就行了。如果x2<=y1,那么就要再分四种情况,一种起点终点都在[x2,y1]内;第二种起点在[x1,x2)内,终点在[x2,y1]内;第三种是起点在[x2,y1]内,终点在(y1,y2]内;最后一种是起点在[x1,x2)内,终点在(y1,y2]内。这些计算相应区间和还有最大前缀后缀就能算出来了。
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<map> #include<queue> #include<stack> #include<cmath> #include<vector> #define inf 0x3f3f3f3f #define Inf 0x3FFFFFFFFFFFFFFFLL #define eps 1e-9 #define pi acos(-1.0) using namespace std; typedef long long ll; using namespace std; const int maxn=10000+10; int sum[maxn],maxv[maxn<<2],pre[maxn<<2],suff[maxn<<2]; void PushUp(int l,int r,int rt) { int m=(l+r)>>1; maxv[rt]=max(maxv[rt<<1],maxv[rt<<1|1]); maxv[rt]=max(maxv[rt],pre[rt<<1|1]+suff[rt<<1]); pre[rt]=max(pre[rt<<1],sum[m]-sum[l-1]+pre[rt<<1|1]); suff[rt]=max(suff[rt<<1|1],sum[r]-sum[m]+suff[rt<<1]); } void build(int l,int r,int rt) { if(l==r) { maxv[rt]=pre[rt]=suff[rt]=sum[r]-sum[l-1]; return ; } int m=(l+r)>>1; build(l,m,rt<<1); build(m+1,r,rt<<1|1); PushUp(l,r,rt); } int Query(int L,int R,int l,int r,int rt,int &psum,int &pmax,int &smax) { if(l>=L&&r<=R) { pmax=pre[rt]; smax=suff[rt]; psum=sum[r]-sum[l-1]; return maxv[rt]; } int m=(l+r)>>1; if(m>=R) return Query(L,R,l,m,rt<<1,psum,pmax,smax); else if(m<L) return Query(L,R,m+1,r,rt<<1|1,psum,pmax,smax); else { int s,p1,p2,su1,su2,ss1,ss2; s=max(Query(L,R,l,m,rt<<1,ss1,p1,su1),Query(L,R,m+1,r,rt<<1|1,ss2,p2,su2)); s=max(s,su1+p2); pmax=max(p1,ss1+p2); smax=max(su2,ss2+su1); psum=ss1+ss2; return s; } } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int t,n; scanf("%d",&t); while(t--) { scanf("%d",&n); sum[0]=0; for(int i=1;i<=n;++i) { scanf("%d",&sum[i]); sum[i]+=sum[i-1]; } build(1,n,1); int q,x1,y1,x2,y2,l,r,ans; int pp,ss,pt; scanf("%d",&q); while(q--) { scanf("%d%d%d%d",&x1,&y1,&x2,&y2); ans=-inf; if(y1<x2) { ans=sum[x2]-sum[y1-1]; l=x1;r=y1-1; if(l<=r) { Query(l,r,1,n,1,pt,pp,ss); if(ss>0) ans+=ss; } l=x2+1;r=y2; if(l<=r) { Query(l,r,1,n,1,pt,pp,ss); if(pp>0) ans+=pp; } } else { int tmp,p1,s1; l=x2;r=y1; ans=Query(l,r,1,n,1,pt,p1,s1); tmp=sum[y1]-sum[x2-1]; l=x1;r=x2-1; if(l<=r) { Query(l,r,1,n,1,pt,pp,ss); tmp+=ss; ans=max(ans,p1+ss); } l=y1+1;r=y2; if(l<=r) { Query(l,r,1,n,1,pt,pp,ss); tmp+=pp; ans=max(ans,s1+pp); } ans=max(ans,tmp); } printf("%d\n",ans); } } return 0; }
相关文章推荐
- SPOJ 2916 Can you answer these queries V(线段树-分类讨论)
- Spoj 2916 Can you answer these queries V 线段树 求任意重叠区间的最大子段和
- SPOJ 2916 Can you answer these queries V(GSS5 线段树)
- 【SPOJ】2916 Can you answer these queries V 线段树
- GSS5 spoj 2916. Can you answer these queries V 线段树
- 【SPOJ - GSS2】Can you answer these queries II(线段树)
- SPOJ 1557. Can you answer these queries II (很强的线段树)
- SPOJ GSS1 Can you answer these queries I (线段树求区间最大连续和)
- SPOJ 2713. Can you answer these queries IV(GSS4 线段树)
- Spoj 1557 Can you answer these queries II 线段树 随意区间最大子段和 不反复数字
- Spoj 1557 Can you answer these queries II 线段树 任意区间最大子段和 不重复数字
- SPOJ GSS1 Can you answer these queries I[线段树]
- 【SPOJ】2916 Can you answer these queries V
- spoj 1716. Can you answer these queries III(线段树)
- SPOJ GSS3 Can you answer these queries III[线段树]
- [SPOJ GSS5] Can you answer these queries V [线段树]
- SPOJ GSS1 Can you answer these queries I ——线段树
- SPOJ 2713 Can you answer these queries IV(线段树)
- spoj 1716 Can you answer these queries III(线段树)
- SPOJ 2916 Can you answer these queries V