[COGS 755]山海经:线段树

网上似乎这道题的题解很少?写一个吧
我跟这道题的渊源追溯到了上个学期刚刚学线段树的那一天。。。
当时线段树专题前边的题都是一些板子就不一会就水过了,然后就看到了最后一题的它:山海经
那一个上午,我竭尽全力,却毫无收获。
后来我下午继续肛还是肛不动,但是mikufun大神,在刚学线段树的阶段,把这道我现在都要写30min的难题给A了!
他当时的NB代码:
#include<iostream>
#include<cstdio>
using namespace std;
struct tree{
int l,r,da,dam,dal,dar;
int lme,lmr,le,lr;
}t[];
void build(int l1,int r1,int k){
t[k].l=l1,t[k].r=r1;
if(l1==r1){
scanf("%d",&t[k].da);
t[k].dal=t[k].dam=t[k].dar=t[k].da;
t[k].le=t[k].lme=t[k].lmr=t[k].lr=l1;
return;
}
int mid=(l1+r1)/;
build(l1,mid,k*);
build(mid+,r1,k*+);
t[k].da=t[k*].da+t[k*+].da;
if(t[k*].dal>=t[k*].da+t[k*+].dal){
t[k].dal=t[k*].dal;
t[k].le=t[k*].le;
}
else{
t[k].dal=t[k*].da+t[k*+].dal;
t[k].le=t[k*+].le;
}
if(t[k*+].dar>t[k*+].da+t[k*].dar){
t[k].dar=t[k*+].dar;
t[k].lr=t[k*+].lr;
}
else{
t[k].dar=t[k*+].da+t[k*].dar;
t[k].lr=t[k*].lr;
}
if(max(t[k*].dam,max(t[k*+].dam,t[k*].dar+t[k*+].dal))==t[k*].dam){
t[k].dam=t[k*].dam;
t[k].lme=t[k*].lme;t[k].lmr=t[k*].lmr;
}
else if(max(t[k*].dam,max(t[k*+].dam,t[k*].dar+t[k*+].dal))==t[k*+].dam){
t[k].dam=t[k*+].dam;
t[k].lme=t[k*+].lme;t[k].lmr=t[k*+].lmr;
}
else if(max(t[k*].dam,max(t[k*+].dam,t[k*].dar+t[k*+].dal))==t[k*].dar+t[k*+].dal){
t[k].dam=t[k*].dar+t[k*+].dal;
t[k].lme=t[k*].lr;t[k].lmr=t[k*+].le;
}
}
inline int sea_qu(int l1,int r1,int k,int x,int &ll,int &rr){
if(l1<=t[k].l&&t[k].r<=r1){
if(!x){
ll=t[k].lme;rr=t[k].lmr;
return t[k].dam;
}
if(x==){
ll=t[k].lr;rr=t[k].r;
return t[k].dar;
}
if(x==){
ll=t[k].l;rr=t[k].le;
return t[k].dal;
}
}
int mid=(t[k].l+t[k].r)/,ans,a1,a2,a3,a4,a5,a6;
int a,b,c,d,e,g,h,z;
if(x==){
a1=sea_qu(l1,r1,k*+,,a,b);
ll=a;rr=t[k].r;
if(l1<=mid){
a5=sea_qu(l1,r1,k*,,b,c)+t[k*+].da;
if(a5>a1){
ll=b,rr=t[k].r;
return a5;
}
}
return a1;
}
if(x==){
a2=sea_qu(l1,r1,k*,,z,c);
rr=c;ll=t[k].l;
if(r1>mid){
a6=sea_qu(l1,r1,k*+,,b,z)+t[k*].da;
if(a6>a2){
ll=t[k].l,rr=z;
return a6;
}
}
return a2;
}
if(!x){
if(r1<=mid){
ans=sea_qu(l1,r1,k*,,ll,rr);
return ans;
}
if(l1>mid){
ans=sea_qu(l1,r1,k*+,,ll,rr);
return ans;
}
a1=sea_qu(l1,r1,k*,,a,b);
a2=sea_qu(l1,r1,k*+,,b,c);
a3=sea_qu(l1,r1,k*,,h,d);
a4=sea_qu(l1,r1,k*+,,e,g);
if(max(a1+a2,max(a3,a4))==a3){
ll=h,rr=d;
return a3;
}
if(max(a1+a2,max(a3,a4))==a1+a2){
ll=a;
rr=c;
return a1+a2;
}
if(max(a1+a2,max(a3,a4))==a4){
ll=e,rr=g;
return a4;
}
}
}
int main(){
int n,m,x,y,ll,rr;
scanf("%d%d",&n,&m);
build(,n,);
for(int i=;i<=m;i++){
scanf("%d%d",&x,&y);
int ans=sea_qu(x,y,,,ll,rr);
cout<<ll<<" "<<rr<<" "<<ans<<endl;
}
return ;
}
这可是在当时,也就是没有题能打50行+的时候啊。
我当时看到有人A了都惊呆了。
我就去问mikufun,然后他说:“自己再想一想。”
我后来就一直想A掉这道题,可总有一些理由阻挡我蹒跚前进的脚步。
但现在我终于A了,很轻松释然。
我记得当时老吕看只有mikufunA了这道题,鼓励我们:“没事,只要知识没有丢,这些题你们以后看都很简单的。”
可是我当时想:“这么难的题,我恐怕一辈子都做不对了。”没想到啊,才几个月,变化已经这么大了。
OI改变你我。
题解:线段树维护左端点开始的最大值,右端点开始的最大值,区间最大值,以及它们的端点。
在子树合并到父亲时,父亲左端点开始的最大值可以由左儿子左端点开始的最大值,左儿子全部值+右左端点开始的最大值来更新。
同理于父亲右端点开始的最大值,区间最大值。但区间最大值还能够由左儿子右端点的最大值+右儿子左端点的最大值来更新。
总体上细节挺多的,注意好它字典序问题。其实就是几个顺序的调整罢了。
在merge合并时,我为了之后的查询更加方便,选择了用结构体进行合并,因为在find查找时由于[a,b]区间会被分成log个区间,因此等效于在子树合并到父亲。
#include<bits/stdc++.h>
#define N 100005
#define Inf 0x7f7f7f7f
#define lch k<<1
#define rch k<<1|1
inline int read(){
int x=,f=;char ch=getchar();
while(!isdigit(ch))f=(ch=='-'?-:),ch=getchar();
while(isdigit(ch))x=x*+ch-'',ch=getchar();
return x*f;
}
struct node{int l,r,mx,lmx,lp,rmx,rp,smx,slp,srp;}tr[N<<];
int n,m;
node merge(const node &t1,const node &t2){
node ret;ret.lmx=ret.rmx=ret.smx=-Inf;
ret.l=t1.l,ret.r=t2.r;ret.mx=t1.mx+t2.mx;
ret.lmx=t1.lmx,ret.lp=t1.lp;
ret.rmx=t2.rmx,ret.rp=t2.rp;
if(t1.smx>=t2.smx) ret.smx=t1.smx,ret.slp=t1.slp,ret.srp=t1.srp;
if(t1.rmx+t2.lmx>ret.smx) ret.smx=t1.rmx+t2.lmx,ret.slp=t1.rp,ret.srp=t2.lp;
if(t1.rmx+t2.lmx==ret.smx&&( (t1.rp<ret.slp) || (t1.rp==ret.slp && t2.lp<ret.srp) )) ret.smx=t1.rmx+t2.lmx,ret.slp=t1.rp,ret.srp=t2.lp;
if(t2.smx>ret.smx) ret.smx=t2.smx,ret.slp=t2.slp,ret.srp=t2.srp;
if(t1.mx+t2.lmx>ret.lmx) ret.lmx=t1.mx+t2.lmx,ret.lp=t2.lp;
if(t2.mx+t1.rmx>ret.rmx) ret.rmx=t2.mx+t1.rmx,ret.rp=t1.rp;
if(ret.smx<=ret.lmx) ret.slp=ret.l,ret.srp=ret.lp;
if(ret.smx<ret.rmx) ret.slp=ret.rp,ret.srp=ret.r;
return ret;
}
void build(int k,int l,int r){
tr[k].l=l,tr[k].r=r;
if(l==r){tr[k].mx=tr[k].lmx=tr[k].rmx=tr[k].smx=read();tr[k].lp=tr[k].rp=tr[k].slp=tr[k].srp=l;return;}
const int mid=(l+r)>>;
build(lch,l,mid),build(rch,mid+,r);
tr[k]=merge(tr[lch],tr[rch]);
}
node find(int k,int l,int r){
if(tr[k].l>=l&&tr[k].r<=r) return tr[k];
node ret;
if(l<=tr[lch].r&&r>=tr[rch].l) ret=merge(find(lch,l,r),find(rch,l,r));
else if(r<=tr[lch].r) ret=find(lch,l,r);
else if(l>=tr[rch].l) ret=find(rch,l,r);
return ret;
}
int main(){
n=read(),m=read();
build(,,n);
int a,b;
for(int i=;i<=m;++i){
a=read(),b=read();
node ret=find(,a,b);
printf("%d %d %d\n",ret.slp,ret.srp,ret.smx);
}
}
我的超短超帅代码
[COGS 755]山海经:线段树的更多相关文章
- COGS 577 蝗灾 线段树+CDQ分治
第一次写cdq分治 感谢hhd<y 这20亿对CP的指导(逃) 其实 就是 递归看左半部分对右半部分的贡献 (树状数组写挂了--临时改的线段树[大写的尴尬]) //By SiriusRen ...
- COGS 2638. 数列操作ψ 线段树
传送门 : COGS 2638. 数列操作ψ 线段树 这道题让我们维护区间最大值,以及维护区间and,or一个数 我们考虑用线段树进行维护,这时候我们就要用到吉司机线段树啦 QAQ 由于发现若干次an ...
- cogs 2554. [福利]可持久化线段树
题目链接 cogs 2554. [福利]可持久化线段树 题解 没有 代码 #include<cstdio> #include<cstring> #include<algo ...
- 【BZOJ 1901】Zju2112 Dynamic Rankings &&【COGS 257】动态排名系统 树状数组套线段树
外面是树状数组,里面是动态开点线段树,对于查询我们先把有关点找出来,然后一起在线段树上行走,这样就是单个O(log2)的了 #include <cstdio> #include <v ...
- AC日记——[福利]可持久化线段树 cogs 2554
2554. [福利]可持久化线段树 ★★☆ 输入文件:longterm_segtree.in 输出文件:longterm_segtree.out 简单对比时间限制:3 s 内存限制:2 ...
- Cogs 1688. [ZJOI2008]树的统计Count(树链剖分+线段树||LCT)
[ZJOI2008]树的统计Count ★★★ 输入文件:bzoj_1036.in 输出文件:bzoj_1036.out 简单对比 时间限制:5 s 内存限制:162 MB [题目描述] 一棵树上有n ...
- cogs 1361. 树 线段树
1361. 树 ★ 输入文件:treed.in 输出文件:treed.out 简单对比时间限制:1 s 内存限制:128 MB [问题描述] 在一个凉爽的夏夜,xth和rabbit来到 ...
- cogs 247. 售票系统 线段树
247. 售票系统 ★★☆ 输入文件:railway.in 输出文件:railway.out 简单对比时间限制:1 s 内存限制:128 MB [问题描述] 某次列车途经C个城市,城市 ...
- cogs 182. [USACO Jan07] 均衡队形 线段树
182. [USACO Jan07] 均衡队形 ★★☆ 输入文件:lineup.in 输出文件:lineup.out 简单对比时间限制:4 s 内存限制:128 MB 题目描述 农夫约 ...
随机推荐
- PyQt4 Python GUI窗体应用程序
目录 目录 前言 软件环境 PyQT简介 Setup PyCharm Setup SIP Setup PyQt4 测试PyQt是否安装成功 常见错误 最后 前言 还是一句老话,公司要什么我就做什么.这 ...
- GitHub Port 443 Refused
最近在本地Github上传和更新远程仓库的时候老是显示 GitHub - failed to connect to github 443 windows/ Failed to connect to g ...
- python3实现自动化框架robotframework(最新)
# python3.6及以上版本兼容RIDE1.7.3版本由于最近RIDE1.7.3的版本改进,RIDE这个版本对高版本的wxpython兼容很好,python3.6及以上版本都可以顺利运行RIDE为 ...
- Django ModelChoiceField:过滤查询集并将默认值设置为对象
我有一个Django Form类定义喜欢这个在Models: class AccountDetailsForm(forms.Form): ... adminuser = forms.ModelChoi ...
- [JavaScript] console.log只在查看时才会读取这个打印的对象,并把此刻相关属性和值显示出来
/** * 写个函数解决console.log只在查看时才会读取这个打印的对象,并把此刻相关属性和值显示出来 * @param arg */ const log = function (...ar ...
- [Vuejs] 点击单选框触发两次点击事件的处理
<el-radio-group v-model="uploadStatus" class="upload-status-radio"> <el ...
- (转).net中的session与cookies区别及使用方法
cookie数据存放在客户的浏览器上,session数据放在服务器上,cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,考虑到安全应当使用session 先介绍一 ...
- HttpServletResponse ServletResponse 返回响应 设置响应头设置响应正文体 重定向 常用方法 如何重定向 响应编码 响应乱码
原文地址:HttpServletResponse ServletResponse 返回响应 设置响应头设置响应正文体 重定向 常用方法 如何重定向 响应编码 响应乱码 HttpServletRespo ...
- 思考--mysql 分库分表的思考
查询不在分库键上怎么办,扫描所有库?由于分库了,每个库扫描很快?所以比单个表的扫描肯定快,可以这样理解吗. 多表jion怎么弄,把内层表发给每个分库吗? citus,tidb 都有这些问题,citus ...
- MySQL 用 limit 为什么会影响性能?
一,前言 首先说明一下MySQL的版本: mysql> select version();+-----------+| version() |+-----------+| 5.7.17 |+-- ...