您的位置:首页 > 产品设计 > UI/UE

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]内。这些计算相应区间和还有最大前缀后缀就能算出来了。



代码:



#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: