所谓splay斜率优化dp,就是利用splay和斜率对dp进行优化

(逃)

解析

在斜优的时候,有时我们会发现我们插入的点的横坐标并不单调
这个时候我们就无法利用单调队列维护凸包了
这时,我们就要请出今天的主角:splay

插点

splay斜优最容易错的一个地方
我们维护一个以结点横坐标作为关键值的splay
结点记录第信息有:左右儿子、父亲、xy坐标、分别与左右两边第一个结点的斜率
注意这个第一个结点不一定是左右儿子!
特别的,没有儿子时赋值成正(右)负(左)无穷

step1

首先,让我们把结点按照splay的常规操作塞进去

if(!rt){rt=New(x,y,id,0);lk[rt]=-2e18;rk[rt]=2e18;return;}int now=rt;while(1){if(tr[now][x>dx[now]]) now=tr[now][x>dx[now]];else{tr[now][x>dx[now]]=New(x,y,id,now);splay(tot);break;}}

step2

但是这样,可能凸包的性质会被打破
我们需要继续维护凸包的性质
首先,这个结点可能会是两边的点变成需要去掉的上凸点
下面以左侧为例

加入一个x点时:

显然,3点和4点应该舍去
原本的点集满足凸包性质的前提下
我们其实只需要找到左边第一个满足 lki<slope(i,x)lk_i<slope(i,x)lki​<slope(i,x)的点 (在本图中就是2)
我们可以在splay上通过类似二分的方法来实现这个操作

inline int pre(){int now=tr[rt][0],res=0;while(now){if(lk[now]<slope(now,rt)+eps){res=now;now=tr[now][1];}else now=tr[now][0];}return res;
}

找到这个pre之后,把pre和当前点之间的点全部删去即可

if(tr[now][0]){int o=pre();//printf("?:\n");splay(o,now);tr[o][1]=0;lk[now]=rk[o]=slope(o,now);}

记得更新斜率!!!

step3

考虑到当前点本身可能就是上凸点
我们特判一下如果是直接把它删掉即可
特判的依据就是lkx>rkxlk_x>rk_xlkx​>rkx​
注意这个特判必须在step2之后!!
为什么?因为x的lk和rk都是在step2求的…

if(lk[now]>rk[now]+eps){int ls=tr[now][0],rs=tr[now][1];f[ls]=0;rt=ls;tr[ls][1]=rs;f[rs]=ls;lk[rs]=rk[ls]=slope(ls,rs);}

查询

对于一个斜率k
找到 lki≤k≤rkilk_i \leq k \leq rk_ilki​≤k≤rki​ 的位置即可
相对比较简单

if(lk[now]>rk[now]+eps){int ls=tr[now][0],rs=tr[now][1];f[ls]=0;rt=ls;tr[ls][1]=rs;f[rs]=ls;lk[rs]=rk[ls]=slope(ls,rs);}

update

本题中的横坐标两两不同,但有些题并非如此,需要特判横坐标相同的情况!
具体而言,只需要在插点的地方这么写:

 int x;//这里维护的上凸包if(!now) rt=New(xx,yy,0),x=rt;else{while(1){if(abs(dx[now]-xx)<eps){if(dy[now]<yy) return;else{dy[now]=yy;splay(now);x=now;break;}}if(tr[now][xx>dx[now]]) now=tr[now][xx>dx[now]];else{tr[now][xx>dx[now]]=New(xx,yy,now);splay(tot);x=tot;break;}}}.......

代码

主函数就变得非常easy!

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define il inline
#define debug(a) fprintf(stderr,a)
const int N=5e5+1000;
const int M=3e6+100;
const int mod=998244353;
const double eps=1e-10;
inline ll read(){ll x=0,f=1;char c=getchar();while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}while(isdigit(c)){x=x*10+c-'0';c=getchar();}return x*f;
}
int n,m;
int tr[N][2],f[N],idx[N],rt,tot;
double lk[N],rk[N],dx[N],dy[N];
inline int New(double x,double y,int id,int fa){++tot;tr[tot][0]=tr[tot][1]=0;f[tot]=fa;dx[tot]=x;dy[tot]=y;idx[tot]=id;return tot;
}
inline bool which(int x){return tr[f[x]][1]==x;}
inline void rotate(int x){int fa=f[x],gfa=f[fa];int d=which(x),son=tr[x][d^1];f[x]=gfa;if(gfa) tr[gfa][which(fa)]=x;f[fa]=x;tr[x][d^1]=fa;if(son) f[son]=fa;tr[fa][d]=son;return;
}
inline void splay(int x,int goal=0){//printf("x=%d goal=%d fa=%d\n",x,goal,f[x]);for(int fa;(fa=f[x])!=goal;rotate(x)){if(f[fa]!=goal) which(fa)==which(x)?rotate(fa):rotate(x);}if(!goal) rt=x;return;
}
#define slope(u,v) ((dy[v]-dy[u])/(dx[v]-dx[u]))
inline int pre(){int now=tr[rt][0],res=0;while(now){if(lk[now]<slope(now,rt)+eps){res=now;now=tr[now][1];}else now=tr[now][0];}return res;
}
inline int nxt(){int now=tr[rt][1],res=0;while(now){if(rk[now]+eps>slope(rt,now)){res=now;now=tr[now][0];}else now=tr[now][1];}return res;
}
inline void ins(double x,double y,int id){if(!rt){rt=New(x,y,id,0);lk[rt]=-2e18;rk[rt]=2e18;return;}int now=rt;while(1){if(tr[now][x>dx[now]]) now=tr[now][x>dx[now]];else{tr[now][x>dx[now]]=New(x,y,id,now);splay(tot);break;}}//for(int i=1;i<=tot;i++) printf("i=%d ls=%d rs=%d (%.3lf %.3lf)\n",i,tr[i][0],tr[i][1],dx[i],dy[i]);now=rt;if(tr[now][0]){int o=pre();//printf("?:\n");splay(o,now);tr[o][1]=0;lk[now]=rk[o]=slope(o,now);}else lk[now]=-2e18;if(tr[now][1]){int o=nxt();splay(o,now);tr[o][0]=0;rk[now]=lk[o]=slope(o,now);}else rk[now]=2e18;if(lk[now]>rk[now]+eps){int ls=tr[now][0],rs=tr[now][1];f[ls]=0;rt=ls;tr[ls][1]=rs;f[rs]=ls;lk[rs]=rk[ls]=slope(ls,rs);}return;
}
int query(double k){int now=rt;while(1){if(!now) return 0;//printf("now=%d lk=%.3lf rk=%.3lf (%.3lf %.3lf)\n",now,lk[now],rk[now],dx[now],dy[now]);if(lk[now]-eps<=k&&k<=rk[now]+eps) return idx[now];else if(lk[now]+eps>k) now=tr[now][0];else now=tr[now][1];}
}
double ans=2e18;
int v[N];
ll x[N];
double dp[N],r[N];
#define X(o) (-1.0/(2.0*sqrt(r[o])))
#define Y(o) (dp[o]-1.0*x[o]/(2*sqrt(r[o])))
int main() {#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endifn=read();m=read();for(int i=1;i<=n;i++){x[i]=read();r[i]=read();v[i]=read();}dp[1]=v[1];ins(X(1),Y(1),1);//printf("  i=%d dp=%.3lf (%.3lf,%.3lf)\n\n",1,dp[1],X(1),Y(1));for(int i=2;i<=n;i++){//printf("i=%d\n",i);int j=query(x[i]);//printf("  ok\n");dp[i]=dp[j]+1.0*(x[i]-x[j])/(2*sqrt(r[j]))+v[i];//printf("  j=%d i=%d dp=%.3lf (%.3lf,%.3lf)\n\n",j,i,dp[i],X(i),Y(i));ins(X(i),Y(i),i);if(x[i]+r[i]>=m) ans=min(ans,dp[i]);}//printf("ceck:%3lf\n",slope(1,2));printf("%.3lf\n",ans);return 0;
}
/*
3 1
3 1 33 2
1 1 2
3 1 3
*/

洛谷P2497:基站建设(splay、斜率优化)相关推荐

  1. 洛谷 P3195 [HNOI2008]玩具装箱 —— 斜率优化

    This way 题意: 题解: 洛谷的题解就写的蛮好,首先对于斜率优化,先将它的转移方程写出来,然后对于只包含i的设为A,只包含j的设为B,然后对于含有A和B的项就是二元一次方程中的k和x 这个就可 ...

  2. 洛谷4072 SDOI2016征途 (斜率优化+dp)

    首先根据题目中给的要求,推一下方差的柿子. \[v\times m^2 = m\times \sum x^2 - 2 \times sum \times sum +sum*sum\] 所以\(ans ...

  3. [洛谷P3391] 文艺平衡树 (Splay模板)

    初识splay 学splay有一段时间了,一直没写...... 本题是splay模板题,维护一个1~n的序列,支持区间翻转(比如1 2 3 4 5 6变成1 2 3 6 5 4),最后输出结果序列. ...

  4. [USACO18JAN]Lifeguards P 洛谷黑题,单调队列优化DP

    传送门:戳我 这道题有两个版本,S和P,S是K等于1的情况,显然可以用线段树水过. P版本就难了很多,洛谷黑题(NOI/NOI+/CTSC),嘿嘿. 我自己也不是很理解,照着题解写了一遍,然后悟到了一 ...

  5. 洛谷:P2832 行路难(堆优化Dijkstra(错解)bfs(正解) + 记录路径)

    洛谷:P2832 行路难 写这道题确实是行路难- 此题的最短路约束不只是边权,还有边数(每经过一条边,之后经过的边权值都 +1+1+1 ) 从期望的角度分析,我们肯定是想 尽可能走的路程越短,走得路径 ...

  6. 【BZOJ1096】仓库建设,斜率优化DP练习

    传送门 写在前面:前来报道的学弟 思路:这是学习斜率优化后完全自己独立处理出的第一个题吧,感觉自己还是太弱,这么就初步理解斜率优化. 先推转移方程,这个还是比较好弄得 f[i]=c[i]+min(f[ ...

  7. 洛谷2619/bzoj2654 Tree(凸优化+MST)

    bzoj的数据是真的水.. qwq 由于本人还有很多东西不是很理解 qwq 所以这里只写一个正确的做法. 首先,我们会发现,对于你选择白色边的数目,随着数目的上涨,斜率是单调升高的. 那么这时候我们就 ...

  8. 洛谷P3960 列队【Splay】

    题目描述 Sylvia 是一个热爱学习的女♂孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia 所在的方阵中有 n × m n \times m n×m名 ...

  9. 洛谷P3960 列队(Splay)

    传送门 感觉自己好久不打数据结构已经完全不会了orz-- 据说正解树状数组?然而并不会 首先考虑一下每一次操作,就是把一个人从这一行中取出并放到行的最后,再从最后一列取出放到列的最后 那么这两种操作其 ...

最新文章

  1. 2.1 空间配置器(allocator)
  2. Ubuntu基础知识
  3. Activiti 7.1.4 发布,业务流程管理与工作流系统
  4. ASP.NET基础教程-Web 自定义控件的使用-根据属性值从数据库中提取数据并在页面上自动生成一个表格...
  5. 【区块链】认识区块链的基本概念
  6. neo4j cypher_Neo4j:使用Cypher生成实时建议
  7. C语言 指针自增自减加减运算 p++ p+i
  8. 腾讯二面,我被 “赛马” 问题难住了
  9. Android的手势识别
  10. codeforces C. Sonya and Problem Wihtout a Legend(dp or 思维)
  11. 简单的Oracle触发器使用
  12. 现学活用的XPath爬取豆瓣音乐
  13. android 登录 service_如何优雅的实现自己的Android组件化改造?
  14. 深入浅出 SSL 管理配置实战
  15. 04735数据库系统原理(知识点整合)
  16. Windows Azure AppFabric Caching入门简介
  17. 深度学习/机器学习入门基础数学知识整理(八):中心极限定理,一元和多元高斯分布
  18. 芋道Docker部署
  19. java协同过滤算法的演唱会门票售票系统
  20. 信度和效度经典例子_信度、效度、难度、区分度之间有何不同?

热门文章

  1. sql企业管理器_Valentina Studio for mac(开源数据库管理器)
  2. 重力模型matlab代码,STK基础教程.doc
  3. 在linux中查找运行程序句柄,如何查找我的进程在Linux中打开的文件句柄?
  4. 快速修改HTML5,HTML5无刷新修改URL(示例代码)
  5. drbd heartbeat mysql_Heartbeat+DRBD+MySQL Replication故障处理
  6. 霍纳法树形流图中处理机p个数_2009系统结构试卷答案
  7. python转字符_python 字符转换
  8. 使用React hooks,些许又多了不少摸鱼时间
  9. php去掉多字节字符,PHP 面试题 - 如果没有 mb 系列函数,如何切割多字节字符串...
  10. [SpringSecurity]web权限方案_用户注销