终于把这鬼玩意弄完了……

为什么写的这么丑……

(顺便吐槽 routesea)


最短路的状态很显然:\(f[i]\) 表示从第 \(i\) 条线下来的最小代价。

首先明显要把那个式子拆开。直觉告诉我们这应该是个斜率优化。

\[f[i]=\min(f[j]+A(p_i-q_j)^2+B(p_i-q_j)+C)(x_i=y_j,p_i\ge q_j)
\]

\[f[i]=\min(f[j]+Ap_i^2-2Ap_iq_j+Aq_j^2+Bp_i-Bq_j+C)(x_i=y_j,p_i\ge q_j)
\]

\[f[i]=Ap_i^2+Bp_i+C+\min((-2Aq_j)\times p_i+(Aq_j^2-Bq_j+f[j]))(x_i=y_j,p_i\ge q_j)
\]

后面是个明显的斜率优化。(说是明显然而同步赛时 SB 了居然没看出来)

然而具体怎么搞?我的代码又臭又长或许就是在这里……

我的做法是:把线按 \(p\) 排序,从小到大枚举。

每次把起点处的凸包能加线就加线,注意要加的 \(q\le\) 这条线的 \(p\)。由于 \(p\) 从小到大枚举这个很简单。

然后在凸包上二分,把自己这条线加到终点的凸包的候选中。

不过由于我太菜,只想得到 set 维护凸包,所以写得很丑。

然后因为有二分,又要对相邻的线的交点再弄个 set……

无论如何时间复杂度 \(O(m\log m)\)。

#include<bits/stdc++.h>
using namespace std;
const int maxn=400040;
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define ROF(i,a,b) for(int i=(a);i>=(b);i--)
#define MEM(x,v) memset(x,v,sizeof(x))
inline int read(){
int x=0,f=0;char ch=getchar();
while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
return f?-x:x;
}
struct edge{
int u,v,p,q,id;
bool operator<(const edge &e)const{return q<e.q;}
}e[maxn];
bool cmp(edge e1,edge e2){return e1.p<e2.p;}
struct item{
int k,b;
bool operator<(const item &i)const{
if(k!=i.k) return k>i.k;
return b>i.b;
}
};
struct point{
double x;
int k,b;
bool operator<(const point &f)const{return x<f.x;}
};
int n,m,A,B,C,ans=2e9,f[maxn];
set<edge> in[maxn];
set<item> hull[maxn];
set<point> pt[maxn];
double interx(item i1,item i2){
return i1.k==i2.k?1e10:1.0*(i2.b-i1.b)/(i1.k-i2.k);
}
void remove(int id,set<item>::iterator it){
set<item>::iterator it1=it,it2=it;
it2++;
if(it1!=hull[id].begin()){
it1--;
pt[id].erase((point){interx(*it1,*it),it1->k,it1->b});
it1++;
}
if(it2!=hull[id].end()) pt[id].erase((point){interx(*it,*it2),it->k,it->b});
if(it1!=hull[id].begin() && it2!=hull[id].end()){
it1--;
pt[id].insert((point){interx(*it1,*it2),it1->k,it1->b});
}
hull[id].erase(it);
}
void insert(int id,item x){
set<item>::iterator it=hull[id].insert(x).first;
set<item>::iterator it1=it,it2=it;it2++;
if(it1!=hull[id].begin()){
it1--;
if(it->k==it1->k) hull[id].erase(it1);
else it1++;
}
if(it2!=hull[id].end()){
if(it->k==it2->k) return void(hull[id].erase(it));
}
it1=it2=it=hull[id].find(x);it2++;
if(it1!=hull[id].begin() && it2!=hull[id].end()){
it1--;
if(interx(x,*it1)>interx(x,*it2)) return void(hull[id].erase(x));
}
it=it1=it2=hull[id].find(x);it2++;
if(it1!=hull[id].begin() && it2!=hull[id].end()){
it1--;
pt[id].erase((point){interx(*it1,*it2),it1->k,it1->b});
it1++;
}
if(it1!=hull[id].begin()){
it1--;
pt[id].insert((point){interx(*it1,*it),it1->k,it1->b});
}
if(it2!=hull[id].end()) pt[id].insert((point){interx(*it,*it2),it->k,it->b});
it=it1=hull[id].find(x);
while(it1!=hull[id].begin()){
it1--;
if(it1==hull[id].begin()) break;
it2=it1;it2--;
if(interx(x,*it2)>interx(x,*it1)) remove(id,it1);
else break;
it=it1=hull[id].find(x);
}
it=it1=hull[id].find(x);it1++;
while(it1!=hull[id].end()){
it2=it1;it2++;
if(it2==hull[id].end()) break;
if(interx(x,*it2)<interx(x,*it1)) remove(id,it1);
else break;
it=it1=hull[id].find(x);it1++;
}
}
int main(){
n=read();m=read();A=read();B=read();C=read();
FOR(i,1,m){
int x=read(),y=read(),p=read(),q=read();
e[i]=(edge){x,y,p,q,i};
}
sort(e+1,e+m+1,cmp);
insert(1,(item){0,0});
FOR(i,1,m){
while(!in[e[i].u].empty() && in[e[i].u].begin()->q<=e[i].p){
int q=in[e[i].u].begin()->q,id=in[e[i].u].begin()->id;
insert(e[i].u,(item){-2*A*q,A*q*q-B*q+f[id]});
in[e[i].u].erase(in[e[i].u].begin());
}
if(hull[e[i].u].empty()) continue;
int p=e[i].p,k,b;
set<point>::iterator it=pt[e[i].u].lower_bound((point){e[i].p,-2e9,2e9});
if(it==pt[e[i].u].end()){
set<item>::iterator it=hull[e[i].u].end();it--;
k=it->k;b=it->b;
}
else k=it->k,b=it->b;
f[e[i].id]=A*p*p+B*p+C+k*p+b;
in[e[i].v].insert(e[i]);
if(e[i].v==n) ans=min(ans,f[e[i].id]+e[i].q);
}
printf("%d\n",ans);
}

[NOI2019]回家路线(最短路,斜率优化)的更多相关文章

  1. luogu 5468 [NOI2019]回家路线 最短路/暴力

    想写一个 70 pts 算法,结果数据水,直接就切了 最短路: // luogu-judger-enable-o2 #include<bits/stdc++.h> using namesp ...

  2. [NOI2019]回家路线

    [NOI2019]回家路线 题目大意: 有\(n\)个站点,\(m\)趟车,每趟车在\(p_i\)时从\(x_i\)出发,\(q_i\)时到达\(y_i\). 若小猫共乘坐了\(k\)班列车,依次乘坐 ...

  3. P5468 [NOI2019]回家路线 斜率优化 dp

    LINK:回家路线 (文化课 oi 双爆炸 对 没学上的就是我.(我错了不该这么丧的. 不过还能苟住一段时间.当然是去打NOI了 这道题去年同步赛的时候做过.不过这里再次提醒自己要认真仔细的看题目 不 ...

  4. Luogu P5468 [NOI2019]回家路线 (斜率优化、DP)

    题目链接: (luogu) https://www.luogu.org/problemnew/show/P5468 题解: 爆long long毁一生 我太菜了,这题这么简单考场上居然没想到正解-- ...

  5. NOI2019 回家路线 DP

    「NOI2019」回家路线 链接 loj 思路 f[i][j]第i个点,时间为j,暴力转移 复杂度O(m*t),好像正解是斜率优化,出题人太不小心了233 代码 #include <bits/s ...

  6. 【题解】Luogu P5468 [NOI2019]回家路线

    原题传送门 前置芝士:斜率优化 不会的可以去杜神博客学 这道题我考场上只会拆点跑最短路的70pts做法 后来回家后发现错误的爆搜都能拿满分(刀片) 还有很多人\(O(mt)\)过的,还是要坚持写正解好 ...

  7. P5468 [NOI2019]回家路线

    传送门 看题目一眼斜率优化,然后写半天调不出来 结果错误的 $dfs$ 有 $95$ 分?暴力 $SPFA$ 就 $AC$ 了? 讲讲正解: 显然是斜率优化的式子: 先不考虑 $q_{s_k}$ 的贡 ...

  8. 【斜率优化】【P5468】 [NOI2019]回家路线

    Description 给定 \(n\) 点,这 \(n\) 个点由 \(m\) 班列车穿插连结.对于第 \(i\) 班列车,会在 \(p_i\) 时刻从 \(x_i\) 站点出发开向 \(y_i\) ...

  9. LOJ 3156: 「NOI2019」回家路线

    题目传送门:LOJ #3156. 题意简述: 有一张 \(n\) 个点 \(m\) 条边的有向图,边有两个权值 \(p_i\) 和 \(q_i\)(\(p_i<q_i\))表示若 \(p_i\) ...

随机推荐

  1. 你真的了解nginx重定向URI?-rewrite和alias指令

    未经允许不得转载!最近发现有博主转载我的文章,并没有跟我打招呼,也没有注明出处!!!! 熟悉Nginx的同学都知道Nginx可以用来做负载均衡和反向代理,非常好用.做前后端分离也是非常的方便. 今天我 ...

  2. 如何保障MySQL主从复制关系的稳定性?关键词(新特性、crash-safe)

    一 前言 MySQL 主从架构已经被广泛应用,保障主从复制关系的稳定性是大家一直关注的焦点.MySQL 5.6 针对主从复制稳定性提供了新特性: slave 支持 crash-safe.该功能可以解决 ...

  3. c#的文本格式化形式展示

    假设你使用的是新版本的的c#语法 c#的格式化形式有如下几种 string text = "Hello World!"; Console.WriteLine("Hello ...

  4. 架构设计系列-前端模式的后端(BFF)翻译PhilCalçado

    本文翻译自PhilCalçado的官网:https://philcalcado.com/2015/09/18/the_back_end_for_front_end_pattern_bff.html 对 ...

  5. skeleton在心意web上的实践

    通过手动编写skeleton,在fetch数据时显示skeleton loading,数据拉取成功隐藏skeleton 先看下效果图 在component下创建页面对应的skeleton,然后通过在i ...

  6. docker命令之link

    1.新建两台容器,第二台(busybox_2)link到第一台(busybox_1) [root@localhost ~]# docker run -d -it --name busybox_1 bu ...

  7. CentOS7系统yum方式安装MySQL5.7

    参考:https://www.cnblogs.com/bigbrotherer/p/7241845.html#top 1.在CentOS中默认安装有MariaDB,这个是MySQL的分支,但为了需要, ...

  8. 2019 奥买家java面试笔试题 (含面试题解析)

      本人5年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.奥买家等公司offer,岗位是Java后端开发,因为发展原因最终选择去了奥买家,入职一年时间了,也成为了面试官 ...

  9. Java常用类Date相关知识

    Date:类 Date 表示特定的瞬间,精确到毫秒. 在 JDK 1.1 之前,类 Date 有两个其他的函数.它允许把日期解释为年.月.日.小时.分钟和秒值.它也允许格式化和解析日期字符串. Dat ...

  10. C#中全局作用域的常量、字段、属性、方法的定义与使用

    场景 在开发中,经常会有一些全局作用域的常量.字段.属性.方法等. 需要将这些设置为全局作用域保存且其实例唯一. 注: 博客主页: https://blog.csdn.net/badao_liuman ...