SP2916 GSS5 - Can you answer these queries V 题解--zhengjun

思路

先前缀和一遍,然后就转化成为了区间加,区间查询最值以及区间的最大子段和。

直接上线段树,维护的时候处理一下最大子段和就行了。

代码

#include<bits/stdc++.h>
using namespace std;typedef long long ll;const int N=1e5+10;
int T,n,m,a[N],l1,r1,l2,r2;char op[5];ll sum[N],ans,laz[N<<2];struct zj{ll f,mx,mn;}t[N<<2];
void add(int rt,ll y){t[rt].mx+=y;t[rt].mn+=y;laz[rt]+=y;}
zj merge(zj x,zj y){return {max(max(x.f,y.f),y.mx-x.mn),max(x.mx,y.mx),min(x.mn,y.mn)};}
void pushup(int rt){t[rt]=merge(t[rt<<1],t[rt<<1|1]);}
void pushdown(int rt){if(laz[rt])add(rt<<1,laz[rt]),add(rt<<1|1,laz[rt]),laz[rt]=0;}
void build(int l=0,int r=n,int rt=1){
	laz[rt]=0;if(l==r)return t[rt].mx=t[rt].mn=sum[l],t[rt].f=-1e18,void();int mid=(l+r)>>1;
	build(l,mid,rt<<1);build(mid+1,r,rt<<1|1);pushup(rt);
}
void update(int L,int R,ll x,int l=0,int r=n,int rt=1){
	if(L<=l&&r<=R)return add(rt,x);int mid=(l+r)>>1;pushdown(rt);
	if(L<=mid)update(L,R,x,l,mid,rt<<1);if(mid<R)update(L,R,x,mid+1,r,rt<<1|1);pushup(rt);
}
zj query(int L,int R,int l=0,int r=n,int rt=1){
	if(L<=l&&r<=R)return t[rt];int mid=(l+r)>>1;pushdown(rt);
	if(R<=mid)return query(L,R,l,mid,rt<<1);if(L>mid)return query(L,R,mid+1,r,rt<<1|1);
	return merge(query(L,R,l,mid,rt<<1),query(L,R,mid+1,r,rt<<1|1));
}
int get(){
	scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&a[i]),sum[i]=sum[i-1]+a[i];scanf("%d",&m);build();for(;m--;){
		scanf("%d%d%d%d",&l1,&r1,&l2,&r2);if(l1>r1)swap(l1,r1);if(l2>r2)swap(l2,r2);if(l1>l2)swap(l1,l2),swap(r1,r2);
		r1=min(r1,r2);if(r1<l2)printf("%lld\n",query(l2,r2).mx-query(l1-1,r1-1).mn);else printf("%lld\n",
			max(max(query(r1,r2).mx-query(l1-1,r1-1).mn,query(l2,r2).mx-query(l1-1,l2-1).mn),query(l2-1,r1).f));
	}return 0;
}
int main(){
	for(scanf("%d",&T);T--;)get();return 0;
}
posted @ 2022-07-06 14:13  A_zjzj  阅读(16)  评论(0编辑  收藏  举报