[小白逛公园]|[SP1716]|[UVA1400]解题报告(三合一)

2023-10-21 20:50

本文主要是介绍[小白逛公园]|[SP1716]|[UVA1400]解题报告(三合一),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

其实小白逛公园和SP1716是一道题,UVA1400是升级版....都是线段树

题目链接:

1.小白逛公园(这有题面)

2.SP1716 GSS3 - Can you answer these queries III裸题意在这

3.UVA1400 "Ray, Pass me the dishes!"

题意:

n 个数,q 次操作

操作0 x yA_x 修改为y

操作1 l r询问区间[l, r]的最大子段和

常识数据范围。

思路:这题难在合并,单点修改很容易。我们可以分类讨论,一个区间的最大子段和会从3部分更新过来:

1.左子树的最大子段和。2.右子树的最大子段和。3.跨越左右子树的最大子段和。

前两种情况很容易,直接更新即可,考虑第三种情况怎么更新。

我们开一个结构体

 

struct Tree{ll pre,suf,sub,val;
}tree[N];  

 

pre为当前区间的最大前缀和,suf为当前区间的最大后缀和,sub为当前区间的最大子段和,val为当前区间的和。

可以发现,第三种情况为 左子树的最大后缀和+右子树的最大前缀和。

合并操作分析完毕,接下来只要考虑怎么让代码优雅了.

合并操作代码

inline Tree push_up(R Tree q,R Tree e){//左子树   右子树Tree w;w.pre=max(q.pre,q.val+e.pre);w.suf=max(e.suf,e.val+q.suf);w.sub=max(max(q.sub,e.sub),q.suf+e.pre);w.val=q.val+e.val;return w;
}

还要注意一点,询问的时候,若左右子树只有一个访问到了,一定不能将两个直接合并,因为另一个没有访问的区间不属于这次询问的范围。

询问操作代码:

inline Tree query(R int p,R int l,R int r,R int x,R int y){R Tree w,q,e;R int pd1=0,pd2=0;if(l>=x&&r<=y)return tree[p];R int mid=(l+r)>>1;if(x<=mid){q=query(p<<1,l,mid,x,y);pd1=1;}if(y>mid){e=query(p<<1|1,mid+1,r,x,y);pd2=1;}if(pd1&&pd2)w=push_up(q,e);else if(pd1)w=q;else if(pd2)w=e;return w;
}

完整代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define R register
#define ll long long int
using namespace std;
const int N=500005<<2;
ll n,q,a[N];
struct Tree{ll pre,suf,sub,val;
}tree[N];
inline Tree push_up(R Tree q,R Tree e){Tree w;w.pre=max(q.pre,q.val+e.pre);w.suf=max(e.suf,e.val+q.suf);w.sub=max(max(q.sub,e.sub),q.suf+e.pre);w.val=q.val+e.val;return w;
}
inline void build(R int p,R int l,R int r){if(l==r){tree[p].pre=tree[p].suf=tree[p].sub=tree[p].val=a[l];return;}R int mid=(l+r)>>1;build(p<<1,l,mid);build(p<<1|1,mid+1,r);tree[p]=push_up(tree[p<<1],tree[p<<1|1]);
}
inline void update(R int p,R int l,R int r,R int x,R ll k){//A[x]=kif(l==r){tree[p].pre=tree[p].suf=tree[p].sub=tree[p].val=k;return;}R int mid=(l+r)>>1;if(x<=mid)update(p<<1,l,mid,x,k);else update(p<<1|1,mid+1,r,x,k);tree[p]=push_up(tree[p<<1],tree[p<<1|1]);
}
inline Tree query(R int p,R int l,R int r,R int x,R int y){R Tree w,q,e;R int pd1=0,pd2=0;if(l>=x&&r<=y)return tree[p];R int mid=(l+r)>>1;if(x<=mid){q=query(p<<1,l,mid,x,y);pd1=1;}if(y>mid){e=query(p<<1|1,mid+1,r,x,y);pd2=1;}if(pd1&&pd2)w=push_up(q,e);else if(pd1)w=q;else if(pd2)w=e;return w;
}
int main(){scanf("%lld",&n);for(R int i=1;i<=n;i++)scanf("%lld",&a[i]);build(1,1,n);scanf("%lld",&q);for(R int i=1;i<=q;i++){R int pd,x,y;scanf("%d%d%d",&pd,&x,&y);if(pd==0){update(1,1,n,x,y);}else{Tree w;if(x>y)swap(x,y);w=query(1,1,n,x,y);printf("%lld\n",w.sub);}}return 0;
}
View Code

其实这道题的合并还好,只需要取几个max,Uva1400 的合并才叫恶心,

题意:

 

给出一个长度为n的整数序列D,你的任务是对m个询问做出回答。

 

对于询问(a,b),需要找到两个下标x和y,

 

使得a<=x<=y<=b,并且Dx+Dx+1+....+Dy尽量大。

 

如果有多组满足条件的x和y,x尽量小。

 

如果还有多个解,y应该尽量小。

这道题的结构体需要记录的东西更多:

 

struct Tree{LL pre,suf,sub,val,lch,rch,ll,rr;
// 前缀 后缀 最大字段和 区间和 字段和左端点和右端点 前缀和右端点 后缀和左端点 }tree[N<<2];

 

为什么要多记录这4个东西?它要求的不是最大子段和,而是最大子段和的左右端点,我们考虑合并的时候需要用到最大子段和,前缀和,后缀和,所以我们需要记录这些。

合并的时候需要分类讨论:

1.在保证最大子段和的前提下,x尽量小的情况下,y也尽量小。

上一道题怎么合并的?取了3个max,总共有7种情况,分类讨论就好了,

麻烦...

合并代码:

inline Tree update(Tree q,Tree e,int pos){Tree a;a.pre=a.suf=a.sub=a.val=0;a.val=q.val+e.val;//前缀if((q.val+e.pre)<=q.pre){a.pre=q.pre;a.ll=q.ll;}else//前缀
    {a.pre=q.val+e.pre;a.ll=e.ll;}if((e.val+q.suf)>=e.suf){//后缀a.suf=e.val+q.suf;a.rr=q.rr;}else//后缀
    {a.suf=e.suf;a.rr=e.rr;}if((q.sub>=e.sub)&&(q.sub>=q.suf+e.pre)){//字段和
    a.sub=q.sub;a.lch=q.lch;a.rch=q.rch;}elseif((q.suf+e.pre>=q.sub)&&(q.suf+e.pre>=e.sub))//字段和
    {a.sub=q.suf+e.pre;a.lch=q.rr;a.rch=e.ll;}else//字段和
    {a.sub=e.sub;a.lch=e.lch;a.rch=e.rch;}return a;
}
View Code

完整代码:

//a.pre=max(q.pre,q.val+e.pre);
//a.suf=max(e.suf,e.val+q.suf);原始合并方程
//a.sub=max(max(q.sub,e.sub),q.suf+e.pre);
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define R register
#define LL long long int
using namespace std;
const int N = 5e5+5 ;
LL n,m,d[N],num;
struct Tree{LL pre,suf,sub,val,lch,rch,ll,rr;//前缀   后缀    最大字段和   区间和   左区间  右区间     
}tree[N<<2];
inline void init(){memset(d,0,sizeof(d));memset(tree,0,sizeof(tree));
}
inline Tree update(Tree q,Tree e,int pos){Tree a;a.pre=a.suf=a.sub=a.val=0;a.val=q.val+e.val;//前缀if((q.val+e.pre)<=q.pre){a.pre=q.pre;a.ll=q.ll;}else//前缀
    {a.pre=q.val+e.pre;a.ll=e.ll;}if((e.val+q.suf)>=e.suf){//后缀a.suf=e.val+q.suf;a.rr=q.rr;}else//后缀
    {a.suf=e.suf;a.rr=e.rr;}if((q.sub>=e.sub)&&(q.sub>=q.suf+e.pre)){//字段和
    a.sub=q.sub;a.lch=q.lch;a.rch=q.rch;}elseif((q.suf+e.pre>=q.sub)&&(q.suf+e.pre>=e.sub))//字段和
    {a.sub=q.suf+e.pre;a.lch=q.rr;a.rch=e.ll;}else//字段和
    {a.sub=e.sub;a.lch=e.lch;a.rch=e.rch;}return a;
}
inline void build(R int p,R int l,R int r){if(l==r){tree[p].pre=tree[p].suf=tree[p].sub=tree[p].val=d[l];tree[p].ll=tree[p].rr=tree[p].lch=tree[p].rch=l;return;}R int mid=(l+r)>>1;build(p<<1,l,mid);build(p<<1|1,mid+1,r);tree[p]=update(tree[p<<1],tree[p<<1|1],p);
}
inline Tree query(R int p,R int l,R int r,R int x,R int y){R Tree q,e,w;R int pd1=0,pd2=0;if(l>=x&&r<=y){return tree[p];}R int mid=(l+r)>>1;if(x<=mid){q=query(p<<1,l,mid,x,y);pd1=1;}if(y>mid){e=query(p<<1|1,mid+1,r,x,y);pd2=1;}if(pd1&&pd2)w=update(q,e,p);else if(pd1)w=q;else if(pd2)w=e;return w;
}
int main(){while(~scanf("%lld%lld",&n,&m)){init();num++;printf("Case %lld:\n",num);for(R int i=1;i<=n;i++)scanf("%lld",&d[i]);build(1,1,n);for(R int i=1;i<=m;i++){R int a,b;R Tree c;scanf("%d%d",&a,&b);c=query(1,1,n,a,b);printf("%lld %lld\n",c.lch,c.rch);}}
}
View Code

 

如果你还是无法调对程序,我这有对拍用的随机数代码:

#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<algorithm>
using namespace std;
int main() {freopen("test.in","w",stdout);srand((unsigned)time(NULL));int T = rand()%5 + 1;while(T--) {int n = rand()%10+1,m = rand()%5+1;printf("%d %d\n",n,m);for(int i = 1; i <= n; i++) if(rand()%2){printf("%d ",rand()%100);}else printf("%d ",-rand()%100);printf("\n");for(int i = 1; i <= m; i++) {int l = rand()%n+1,r = rand()%n+1;if(l>r) swap(l,r);printf("%d %d\n",l,r);}}return 0;
}
View Code

 

鬼知道这道题我调了多久...

总结:第一次做到合并的复杂操作,估计其它类型的合并也是类似的方法,至少我会的合并方法不是简单的tree[p]=tree[p<<1]+tree[p<<1|1]了。

 

转载于:https://www.cnblogs.com/sky-zxz/p/9790440.html

这篇关于[小白逛公园]|[SP1716]|[UVA1400]解题报告(三合一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/256880

相关文章

【专题】2024飞行汽车技术全景报告合集PDF分享(附原数据表)

原文链接: https://tecdat.cn/?p=37628 6月16日,小鹏汇天旅航者X2在北京大兴国际机场临空经济区完成首飞,这也是小鹏汇天的产品在京津冀地区进行的首次飞行。小鹏汇天方面还表示,公司准备量产,并计划今年四季度开启预售小鹏汇天分体式飞行汽车,探索分体式飞行汽车城际通勤。阅读原文,获取专题报告合集全文,解锁文末271份飞行汽车相关行业研究报告。 据悉,业内人士对飞行汽车行业

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

Python:豆瓣电影商业数据分析-爬取全数据【附带爬虫豆瓣,数据处理过程,数据分析,可视化,以及完整PPT报告】

**爬取豆瓣电影信息,分析近年电影行业的发展情况** 本文是完整的数据分析展现,代码有完整版,包含豆瓣电影爬取的具体方式【附带爬虫豆瓣,数据处理过程,数据分析,可视化,以及完整PPT报告】   最近MBA在学习《商业数据分析》,大实训作业给了数据要进行数据分析,所以先拿豆瓣电影练练手,网络上爬取豆瓣电影TOP250较多,但对于豆瓣电影全数据的爬取教程很少,所以我自己做一版。 目

开题报告中的研究方法设计:AI能帮你做什么?

AIPaperGPT,论文写作神器~ https://www.aipapergpt.com/ 大家都准备开题报告了吗?研究方法部分是不是已经让你头疼到抓狂? 别急,这可是大多数人都会遇到的难题!尤其是研究方法设计这一块,选定性还是定量,怎么搞才能符合老师的要求? 每次到这儿,头脑一片空白。 好消息是,现在AI工具火得一塌糊涂,比如ChatGPT,居然能帮你在研究方法这块儿上出点主意。是不

【干货分享】基于SSM的体育场管理系统的开题报告(附源码下载地址)

中秋送好礼 中秋佳节将至,祝福大家中秋快乐,阖家幸福。本期免费分享毕业设计作品:《基于SSM的体育场管理系统》。 基于SSM的体育场管理系统的开题报告 一、课题背景与意义 随着全民健身理念的深入人心,体育场已成为广大师生和社区居民进行体育锻炼的重要场所。然而,传统的体育场管理方式存在诸多问题,如资源分配不均、预约流程繁琐、数据统计不准确等,严重影响了体育场的使用效率和用户体验。

作为刚从事Java开发的小白,需要掌握哪些技能

作为一个刚踏入Java开发世界的小白,面对各种技术和工具,你可能会觉得有点不知所措。但是别担心,我会给你一个简单清晰的路线图,让你可以有条不紊地掌握基本技能,逐步成长为一名Java开发者。 1. 扎实的Java基础 Java的基础是你迈向高级开发的重要基石,建议从以下几个方面着手: 语法和基础概念:比如变量、条件语句、循环、方法、数组、面向对象编程(OOP)等等。这些基础如同建房子的地基,越

[SWPUCTF 2021 新生赛]web方向(一到六题) 解题思路,实操解析,解题软件使用,解题方法教程

题目来源 NSSCTF | 在线CTF平台因为热爱,所以长远!NSSCTF平台秉承着开放、自由、共享的精神,欢迎每一个CTFer使用。https://www.nssctf.cn/problem   [SWPUCTF 2021 新生赛]gift_F12 这个题目简单打开后是一个网页  我们一般按F12或者是右键查看源代码。接着我们点击ctrl+f后快速查找,根据题目给的格式我们搜索c

【中国国际航空-注册/登录安全分析报告】

前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 1. 暴力破解密码,造成用户信息泄露 2. 短信盗刷的安全问题,影响业务及导致用户投诉 3. 带来经济损失,尤其是后付费客户,风险巨大,造成亏损无底洞 所以大部分网站及App 都采取图形验证码或滑动验证码等交互解决方案, 但在机器学习能力提高的当下,连百度这样的大厂都遭受攻击导致点名批评, 图形验证及交互验证方式的安全性到底如

小白装修之全屋定制和软装

装修决策方法论:三点走下来 是则是 否则否 第一步:想清楚 哪些 是 真实需求 第二步: 了解这些需求是通过何种方式实现的 第三步:考虑 实现方式的缺点 是否能接受  全屋定制  方式:1.找全屋定制的商家  2.木工现场打柜子 组成:设计 + 板材 + 加工 + 配件 +安装 设计板块:明明有成品家具可以购买 为什么要做定制呢? 自主规划 选设计师 1.更符合我们房屋和物

hdu1879(解题报告)

继续畅通工程                                   Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)