SPOJ GSS5 Can you answer these queries V

You are given a sequence A[1], A[2], ..., A[N] . ( |A[i]| <= 10000 , 1 <= N <= 10000 ). A query is defined as follows: Query(x1,y1,x2,y2) = Max { A[i]+A[i+1]+...+A[j] ; x1 <= i <= y1 , x2 <= j <= y2 and x1 <= x2 , y1 <= y2 }. Given M queries (1 <= M <= 10000), your program must output the results of these queries.

Input

The first line of the input consist of the number of tests cases <= 5. Each case consist of the integer N and the sequence A. Then the integer M. M lines follow, contains 4 numbers x1, y1, x2 y2.

Output

Your program should output the results of the M queries for each test case, one query per line.




参见http://blog.csdn.net/sdfzyhx/article/details/51388593。

当y1<x2时,即起点可选区间与终点可选区间不重叠,则答案为lmax(x1,y1)+sum(y1,x2)+rmax(x2,y2)。

否则,则需对y1和x2所在位置进行讨论。

ans=max(max(x2,y1),rmax(x1,y2)+lmax(y1,y2),rmax(x1,x2)+lmax(x2,y2))。

第一种为两端点都在重叠部分,第二种为起点在独属区域,第三种为终点在独属区域。

【注:此处为了直观,略去边界的+1,-1。详见代码。】

#include<cstdio>
#include<cstring>
#define M(a) memset(a,0,sizeof(a))
struct node
{
	int lch,rch,l,r,lmax,rmax,max,sum;
}t[200010];
struct ans
{
	int l,r,max,s;
};
int n,nn,a[50010];
int mx(int x,int y)
{
	return x>y?x:y;
}
void build(int p,int l,int r)
{
	t[p].l=l;
	t[p].r=r;
	if (l==r)
	{
		t[p].lmax=t[p].rmax=t[p].max=t[p].sum=a[l];
		return;
	}
	int mid=(t[p].l+t[p].r)/2;
	t[p].lch=++nn;
	build(nn,l,mid);
	t[p].rch=++nn;
	build(nn,mid+1,r);
	t[p].sum=t[t[p].lch].sum+t[t[p].rch].sum;
	t[p].lmax=mx(t[t[p].lch].lmax,t[t[p].lch].sum+t[t[p].rch].lmax);
	t[p].rmax=mx(t[t[p].rch].rmax,t[t[p].rch].sum+t[t[p].lch].rmax);
	t[p].max=mx(mx(t[t[p].lch].max,t[t[p].rch].max),t[t[p].lch].rmax+t[t[p].rch].lmax);
}
ans find(int p,int l,int r)
{
	ans al,ar,a;
	if (l>r)
	{
		a.l=a.r=a.s=a.max=0;
		return a;
	}
	if (t[p].l==l&&t[p].r==r)
	{
		a.l=t[p].lmax;
		a.r=t[p].rmax;
		a.max=t[p].max;
		a.s=t[p].sum;
		return a;
	}
	int mid=(t[p].l+t[p].r)/2;
	if (r<=mid) return find(t[p].lch,l,r);
	if (l>=mid+1) return find(t[p].rch,l,r);
	al=find(t[p].lch,l,mid);
	ar=find(t[p].rch,mid+1,r);
	a.l=mx(al.l,al.s+ar.l);
	a.r=mx(ar.r,ar.s+al.r);
	a.s=al.s+ar.s;
	a.max=mx(mx(al.max,ar.max),al.r+ar.l);
	return a;
}
int main()
{
	int i,j,k,m,p,q,x,y,z,T,x1,x2,y1,y2;
	scanf("%d",&T);
	while (T--)
	{
		M(a);
		M(t);
    	scanf("%d",&n);
    	for (i=1;i<=n;i++)
    	  scanf("%d",&a[i]);
    	nn=1;
    	build(1,1,n);
    	scanf("%d",&m);
    	for (i=1;i<=m;i++)
    	{
    		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
    		if (x2<=y1)
    		{
    			x=find(1,x2,y1).max;
    			y=find(1,x1,y1).r+find(1,y1+1,y2).l;
    			z=find(1,x1,x2-1).r+find(1,x2,y2).l;
    			printf("%d\n",mx(mx(x,y),z));
			}
			else
			  printf("%d\n",find(1,x1,y1).r+find(1,y1+1,x2-1).s+find(1,x2,y2).l);
    	}
    }
}







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值