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 }
题目大意
给定一个序列。查询左端点在 [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_2x1≤x2,y1≤y2 ,但是不保证端点所在的区间不重合
题解
看起来很难其实就是分类讨论一下:
如果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,在递归里特判一下,还有就是区间的边界需要注意不要算重了。