SPOJ GSS5 Can you answer these queries V

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #include<cmath>
 6 using namespace std;
 7 const int N=101000;
 8 int a[N],n,m,t;
 9 struct tree{
10     int l,r,sum,lx,rx,maxx;
11 }tr[N*8];
12 void update(int now){
13     int ls=now*2;int rs=now*2+1;
14     tr[now].maxx=max(tr[ls].maxx,max(tr[rs].maxx,tr[ls].rx+tr[rs].lx));
15     tr[now].lx=max(tr[ls].lx,tr[ls].sum+tr[rs].lx);
16     tr[now].rx=max(tr[rs].rx,tr[rs].sum+tr[ls].rx);
17     tr[now].sum=tr[ls].sum+tr[rs].sum;
18 }
19 void build(int l,int r,int now){
20     tr[now].l=l;tr[now].r=r;
21     if(l==r){
22         tr[now].sum=a[l];
23         tr[now].lx=tr[now].rx=tr[now].maxx=a[l];
24         return;
25     }
26     int mid=(tr[now].l+tr[now].r)>>1;
27     build(l,mid,now*2);
28     build(mid+1,r,now*2+1);
29     update(now);
30 }
31 int check(int l,int r,int k,int now){
32     if(l>r)return 0; 
33     if(tr[now].l==l&&tr[now].r==r){
34         if(k==1)return tr[now].maxx;
35         else if(k==4)return tr[now].sum;
36         else if(k==2)return tr[now].rx;
37         else return tr[now].lx;
38     }
39     int mid=(tr[now].l+tr[now].r)>>1;
40     if(l>mid)return check(l,r,k,now*2+1);
41     else if(r<=mid) return check(l,r,k,now*2);
42     else{
43         if(k==1)return max(check(l,mid,1,now*2),max(check(mid+1,r,1,now*2+1),check(l,mid,2,now*2)+check(mid+1,r,3,now*2+1)));
44         else if(k==2)return max(check(mid+1,r,2,now*2+1),check(mid+1,r,4,now*2+1)+check(l,mid,2,now*2));
45         else if(k==3)return max(check(l,mid,3,now*2),check(l,mid,4,now*2)+check(mid+1,r,3,now*2+1));
46         else return check(l,mid,4,now*2)+check(mid+1,r,4,now*2+1);
47     }
48 }
49 int main(){
50     scanf("%d",&t);
51     for(int z=1;z<=t;z++){
52         scanf("%d",&n);
53         for(int i=1;i<=n;i++){
54             scanf("%d",&a[i]);
55         } 
56         build(1,n,1);
57         scanf("%d",&m);
58         for(int i=1,x,y,xx,yy;i<=m;i++){
59             scanf("%d%d%d%d",&x,&y,&xx,&yy);
60             if(xx>y){
61                 printf("%d\n",check(x,y,2,1)+check(y+1,xx-1,4,1)+check(xx,yy,3,1));
62             }else if(y==yy){
63                 printf("%d\n",max(check(xx,yy,1,1),check(xx,yy,3,1)+check(x,xx-1,2,1)));
64             }else{
65                 printf("%d\n",max(check(x,xx-1,2,1)+check(xx,y,3,1),max(check(x,xx-1,2,1)+check(xx,y,4,1)+check(y+1,yy,3,1),max(check(xx,y,2,1)+check(y+1,yy,3,1),check(xx,y,1,1)))));
66             }
67         }
68     } 
69     return 0;
70 }
View Code

 

题目大意

给定一个序列。查询左端点在 [x1,y1][x_1, y_1][x1,y1] 之间,且右端点在 [x2,y2][x_2, y_2][x2,y2] 之间的最大子段和,数据保证 x1≤x2,y1≤y2x_1\leq x_2,y_1\leq y_2x1x2,y1y2 ​ ,但是不保证端点所在的区间不重合

题解

看起来很难其实就是分类讨论一下:

如果x1<=y1<x2<=y2

区间分离,中间必须取,两端区间靠近中间选最大

如果x1<=x2<=y1<=y2

选取[x2,y1]中的最大子段和

选取[x1,x2-1]的最右端部分,和[x2,y1]的最左端部分

选取[x2,y1]的最右端部分,和[y1+1,y2]的最左端部分

选取[x1,x2-1]的最右端部分,[x2,y1]的全部,和[y1+1,y2]的最左端部分

代码还是要注意一些细节,比如,l>r,在递归里特判一下,还有就是区间的边界需要注意不要算重了。

 

posted @ 2018-07-13 08:51  Xu-daxia  阅读(200)  评论(0编辑  收藏  举报