2018.10.16 spoj Can you answer these queries V(线段树)

本文介绍了一道线段树的经典题目,任务是找到左端点在给定范围内的最大子段和,通过分类讨论和巧妙的数据结构实现高效查询。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门
线段树经典题。
就是让你求左端点在 [ l 1 , r 1 ] [l1,r1] [l1,r1]之间,右端点在 [ l 2 , r 2 ] [l2,r2] [l2,r2]之间且满足 l 1 ≤ l 2 , r 1 ≤ r 2 l1\le l2,r1 \le r2 l1l2,r1r2的最大子段和。


直接分类讨论就行了。
如果两个区间不相交的话,答案就是 r m a x ( l 1 , l 2 ) + s u m ( l 2 + 1 , l 2 − 1 ) + l m a x ( l 2 , r 2 ) rmax(l1,l2)+sum(l2+1,l2-1)+lmax(l2,r2) rmax(l1,l2)+sum(l2+1,l21)+lmax(l2,r2)
如果相交的话,讨论一下就是 m a x ( m a x ( r m a x ( l 1 , l 2 ) + l m a x ( l 2 , r 2 ) − v a l [ l 2 ] , r m a x ( l 1 , r 1 ) + l m a x ( r 1 , r 2 ) − v a l [ r 1 ] ) , m i d m a x ( l 2 , r 1 ) ) max(max(rmax(l1,l2)+lmax(l2,r2)-val[l2],rmax(l1,r1)+lmax(r1,r2)-val[r1]),midmax(l2,r1)) max(max(rmax(l1,l2)+lmax(l2,r2)val[l2],rmax(l1,r1)+lmax(r1,r2)val[r1]),midmax(l2,r1))

代码:

#include<bits/stdc++.h>
#define lc (p<<1)
#define rc (p<<1|1)
#define mid (T[p].l+T[p].r>>1)
#define N 10005
using namespace std;
inline int read(){
	int ans=0,w=1;
	char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
	return ans*w;
}
int n,m,a[N],T_T;
struct Node{int l,r,ls,rs,ms,sum;}T[N<<2];
inline Node operator+(const Node&a,const Node&b){
	Node ret;
	ret.l=a.l,ret.r=b.r,ret.sum=a.sum+b.sum;
	ret.ls=max(a.ls,a.sum+b.ls);
	ret.rs=max(b.rs,b.sum+a.rs);
	ret.ms=max(max(a.ms,b.ms),a.rs+b.ls);
	return ret;
}
inline void build(int p,int l,int r){
	T[p].l=l,T[p].r=r;
	if(l==r){T[p].ls=T[p].rs=T[p].ms=T[p].sum=a[l];return;}
	build(lc,l,mid),build(rc,mid+1,r),T[p]=T[lc]+T[rc];
}
inline Node query(int p,int ql,int qr){
	if(ql>T[p].r||qr<T[p].l)return (Node){T[p].l,T[p].r,0,0,0,0};
	if(ql<=T[p].l&&T[p].r<=qr)return T[p];
	if(qr<=mid)return query(lc,ql,qr);
	if(ql>mid)return query(rc,ql,qr);
	return query(lc,ql,mid)+query(rc,mid+1,qr);
}
int main(){
	T_T=read();
	while(T_T--){
		n=read();
		for(int i=1;i<=n;++i)a[i]=read();
		build(1,1,n),m=read();
		while(m--){
			int l1=read(),r1=read(),l2=read(),r2=read();
			if(r1<l2){
				Node ansl=query(1,l1,r1),ansm=query(1,r1+1,l2-1),ansr=query(1,l2,r2);
				printf("%d\n",ansl.rs+ansm.sum+ansr.ls);
			}
			else{
				int ans=query(1,l2,r1).ms;
				if(l1<l2)ans=max(ans,query(1,l1,l2).rs+query(1,l2,r2).ls-a[l2]);
				if(r2>r1)ans=max(ans,query(1,l1,r1).rs+query(1,r1,r2).ls-a[r1]);
				printf("%d\n",ans);
			}
		}
	}
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值