【题解】SP2916 GSS5
GSS5 = GSS1 + 前缀和 + 区间最值
原题链接
其实这道题感觉评分不能上紫
建议先做一下GSS1再做这道题。
好了,我们假设你已经搞懂了GSS1,现在开始讲GSS5(
Case 1
题目给了两个区间 ,先考虑一下两个区间不相交的情况。
对原序列做一下前缀和,用线段树维护一下最大最小值,然后查询的时候就在 找最大,在 找最小,两者相减即可得到最大的子段和。
Case 2
如果两个区间会相交呢?显然这时候直接进行 操作是不正确的。我们对于左右端点所在的区间进行分类讨论。
首先对 和 进行 的操作,由于这里的区间只有一个元素相交,这么做不会出问题。
然后同理地,对 和 进行 的操作。
现在只剩下了查询的两个区间的交集,即 尚未处理。我们发现,这是我们要找的就是区间最大子段和,于是就可以copy下来GSS1的代码(
交了两次才过qAq,看到SPOJ下的评论好多人都一次过了。
代码:
#include <bits/stdc++.h> using namespace std; int T,n,m,a[50005],sum[50005]; typedef long long LL; const int INF=0x7fffffff; struct TreeNode { LL lmax,rmax,maxx; LL sum,mn,mx; TreeNode(): sum(0),mn(INF),mx(-INF) { lmax=rmax=maxx=-INF; } TreeNode(int) { lmax=rmax=maxx=sum=mn=mx=0; } }t[40005]; inline void merge(TreeNode &dst,const TreeNode &a,const TreeNode &b) { dst.lmax=max(a.lmax,a.sum+b.lmax); dst.rmax=max(b.rmax,b.sum+a.rmax); dst.maxx=max({a.maxx,b.maxx,a.rmax+b.lmax}); dst.sum=a.sum+b.sum; dst.mn=min(a.mn,b.mn),dst.mx=max(a.mx,b.mx); } // 用于合并两个区间 #define LC (i<<1) #define RC (i<<1)|1 void build(int l,int r,int i=1) { if(l==r) { t[i].sum=t[i].lmax=t[i].rmax=t[i].maxx=a[l]; t[i].mn=t[i].mx=sum[l]; // 赋初始值 } else { int mid=(l+r)>>1; build(l,mid,LC); build(mid+1,r,RC); merge(t[i],t[LC],t[RC]);// 合并区间 } } TreeNode query(int lq,int rq,int l=1,int r=n,int i=1) { if(lq==rq && lq==0) return TreeNode(0); // 由于线段树在0位置没有存值,需要特殊处理 if(l>=lq && r<=rq) return t[i]; int mid=(l+r)>>1; TreeNode res,x,y; if(mid>=lq) x=query(lq,rq,l,mid,LC); if(mid<rq) y=query(lq,rq,mid+1,r,RC); merge(res,x,y); if(lq<=0) res.mx=max(res.mx,0ll),res.mn=min(res.mn,0ll); // 同理,对于0位置的处理 return res; } main() { scanf("%d",&T); while(T--) { memset(a,0,sizeof(a)); memset(sum,0,sizeof(sum)); memset(t,0,sizeof(t)); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]),sum[i]=sum[i-1]+a[i]; build(1,n); // 建树 scanf("%d",&m); while(m--) { int l1,r1,l2,r2; scanf("%d%d%d%d",&l1,&r1,&l2,&r2); LL ans; if(l2>r1)// Case 1,两区间不相交 ans=query(l2,r2).mx-query(l1-1,r1-1).mn; else// Case 2,两区间相交 ans=max({query(l2,r2).mx-query(l1-1,l2-1).mn,// 左右端点分别在[l1,l2],[l2,r2] query(r1,r2).mx-query(l1-1,r1-1).mn,// 左右端点分别在[l1,r1],[r1,r2] query(l2,r1).maxx});// 查询相交部分的最大子段和 printf("%lld\n",ans); } } return 0; }
本文作者:ExplodingKonjac
本文链接:https://www.cnblogs.com/ExplodingKonjac/p/15066007.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(四):结合BotSharp
· 《HelloGitHub》第 108 期
· Windows桌面应用自动更新解决方案SharpUpdater5发布
· 我的家庭实验室服务器集群硬件清单
· Supergateway:MCP服务器的远程调试与集成工具