[传送门](https://loj.ac/problem/3156)
=
-----
SOL
=
题意:长度为n的路径上有m辆车,每辆车$i$有起点$x_{i}$, 终点$y_{i}$, 上车时间$p_{i}$, 下车时间$q_{i}$ 。问从$1$点上车,通过换乘到达$n$号点的最小代价。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190716165620585.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMDQwNjU1,size_16,color_FFFFFF,t_70)
注意:只能在下车点上车。
=
-----
SOL
=
题意:长度为n的路径上有m辆车,每辆车$i$有起点$x_{i}$, 终点$y_{i}$, 上车时间$p_{i}$, 下车时间$q_{i}$ 。问从$1$点上车,通过换乘到达$n$号点的最小代价。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190716165620585.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzMDQwNjU1,size_16,color_FFFFFF,t_70)
注意:只能在下车点上车。
----
**一、考虑dp**
虽然不满足$x_{i}<y_{i}$,但是有时间限制,且$p_{i}<q_{i}$,所以不会有后效性。
不难发现状态总量为$O(m)$,有$dp[i]$ 表示坐第$i$辆车,在$q_{i}$时间到达$y_{i}$的最小代价
(总时间$q_{s_{k}}$最后加入答案)
$$dp[i]=min(dp[j]+A*(p_{i}-q_{j})*(p_{i}-q_{j})+B*(p_{i}-q_{j})+C)$$
且满足$x_{i}=y_{j}$,$p_{i}>=q_{j}$。
对方程变形
$$2*A*p_{i} * q_{j}+dp[i]-(A*p_{i}*p_{i}+B*p_{i}+C)=dp[j]+A*q_{j}*q_{j}-B*q_{j}$$
对于决策点对$(x,y)$,有$x=q_{j}$,$y=dp[j]+A*q_{j}*q_{j}-B*q_{j}$。
---
**二、考虑决策集合的维护。**
对于每辆车的起点终点$u,v$,维护$t$时间下的凸包集合。集合内决策点满足$q_{i}<=t$.
**二、考虑决策集合的维护。**
对于每辆车的起点终点$u,v$,维护$t$时间下的凸包集合。集合内决策点满足$q_{i}<=t$.
法一:$O(m* log m)$
用$set$装下$u,v$的待加入点,在讨论当前$x_{i}$时,先按$q_{i}$从小到大加入。
法二:$O(m)$
桶排排序
将决策点$j$在$q_{j}$时间,加入$y[j]$的凸包中。对于当前点$i$,询问$p_{i}$时间下$x_{i}$的凸包。
用$set$装下$u,v$的待加入点,在讨论当前$x_{i}$时,先按$q_{i}$从小到大加入。
法二:$O(m)$
桶排排序
将决策点$j$在$q_{j}$时间,加入$y[j]$的凸包中。对于当前点$i$,询问$p_{i}$时间下$x_{i}$的凸包。
-----
CODE
=
$O(m)$
```cpp
//O(m)
#include<bits/stdc++.h>
using namespace std;
#define sf scanf
#define pf printf
#define ll long long
#define in red()
#define cs const
#define gc getchar()
#define db double
#define rint register int
#define se second
#define fi first
inline int red(){
int num=0,f=1;char c=gc;
for(;!isdigit(c);c=gc)if(c=='-')f=-1;
for(;isdigit(c);c=gc)num=(num<<1)+(num<<3)+(c^48);
return num*f;
}
cs int N=2e5+10;
struct pi{
ll x,y;
int id;
};
int p[N],q[N],x[N],y[N],n,m,A,B,C,head[N];
queue<int> res[3100];
vector<pi> que[N];
vector<int> d[3200];
ll dp[N],ans=1e18;
inline db slope(cs pi &a,cs pi &b){
return 1.0*(a.y-b.y)/(1.0*(a.x-b.x));
}
inline void getin(cs int &i){
int pos=y[i];
pi now=(pi){q[i],dp[i]+A*q[i]*q[i]-B*q[i],i};
while(que[pos].size()-head[pos]>=2){
int len=que[pos].size();
if(slope(que[pos][len-1],que[pos][len-2])<slope(que[pos][len-2],now))break;
que[pos].pop_back();
}
que[pos].push_back(now);
}
inline void getout(cs db &slp,cs int &pos){
while(que[pos].size()-head[pos]>=2){
if(slope(que[pos][head[pos]],que[pos][head[pos]+1])>slp)return;
++head[pos];
}
}
signed main(){
n=in,m=in,A=in,B=in,C=in;
for(rint i=1;i<=m;++i){
x[i]=in,y[i]=in,p[i]=in,q[i]=in;
}
for(rint i=1;i<=m;++i)d[p[i]].push_back(i);
que[1].push_back((pi){0,0,0});
int i;
for(rint t=0;t<=3000;++t){
while(!res[t].empty())getin(res[t].front()),res[t].pop();
int len=d[t].size();
for(rint tmp=0;tmp<len;++tmp){
int i=d[t][tmp];
int pos=x[i];
if(que[pos].size()<=head[pos])continue;
db slp=2.0*A*p[i];
getout(slp,pos);
int j=que[pos][head[pos]].id;
dp[i]=dp[j]+1ll*A*(p[i]-q[j])*(p[i]-q[j])+1ll*B*(p[i]-q[j])+C;
res[q[i]].push(i);
if(y[i]==n){
ans=min(ans,dp[i]+q[i]);
}
}
}
cout<<ans;
return 0;
}
CODE
=
$O(m)$
```cpp
//O(m)
#include<bits/stdc++.h>
using namespace std;
#define sf scanf
#define pf printf
#define ll long long
#define in red()
#define cs const
#define gc getchar()
#define db double
#define rint register int
#define se second
#define fi first
inline int red(){
int num=0,f=1;char c=gc;
for(;!isdigit(c);c=gc)if(c=='-')f=-1;
for(;isdigit(c);c=gc)num=(num<<1)+(num<<3)+(c^48);
return num*f;
}
cs int N=2e5+10;
struct pi{
ll x,y;
int id;
};
int p[N],q[N],x[N],y[N],n,m,A,B,C,head[N];
queue<int> res[3100];
vector<pi> que[N];
vector<int> d[3200];
ll dp[N],ans=1e18;
inline db slope(cs pi &a,cs pi &b){
return 1.0*(a.y-b.y)/(1.0*(a.x-b.x));
}
inline void getin(cs int &i){
int pos=y[i];
pi now=(pi){q[i],dp[i]+A*q[i]*q[i]-B*q[i],i};
while(que[pos].size()-head[pos]>=2){
int len=que[pos].size();
if(slope(que[pos][len-1],que[pos][len-2])<slope(que[pos][len-2],now))break;
que[pos].pop_back();
}
que[pos].push_back(now);
}
inline void getout(cs db &slp,cs int &pos){
while(que[pos].size()-head[pos]>=2){
if(slope(que[pos][head[pos]],que[pos][head[pos]+1])>slp)return;
++head[pos];
}
}
signed main(){
n=in,m=in,A=in,B=in,C=in;
for(rint i=1;i<=m;++i){
x[i]=in,y[i]=in,p[i]=in,q[i]=in;
}
for(rint i=1;i<=m;++i)d[p[i]].push_back(i);
que[1].push_back((pi){0,0,0});
int i;
for(rint t=0;t<=3000;++t){
while(!res[t].empty())getin(res[t].front()),res[t].pop();
int len=d[t].size();
for(rint tmp=0;tmp<len;++tmp){
int i=d[t][tmp];
int pos=x[i];
if(que[pos].size()<=head[pos])continue;
db slp=2.0*A*p[i];
getout(slp,pos);
int j=que[pos][head[pos]].id;
dp[i]=dp[j]+1ll*A*(p[i]-q[j])*(p[i]-q[j])+1ll*B*(p[i]-q[j])+C;
res[q[i]].push(i);
if(y[i]==n){
ans=min(ans,dp[i]+q[i]);
}
}
}
cout<<ans;
return 0;
}
```
-----
$O(m*logm)$
```cpp
//O(m*logm)
#include<bits/stdc++.h>
using namespace std;
#define sf scanf
#define pf printf
#define ll long long
#define in red()
#define cs const
#define gc getchar()
#define db double
#define rint register int
#define se second
#define fi first
inline int red(){
int num=0,f=1;char c=gc;
for(;!isdigit(c);c=gc)if(c=='-')f=-1;
for(;isdigit(c);c=gc)num=(num<<1)+(num<<3)+(c^48);
return num*f;
}
cs int N=2e5+10;
struct pi{
ll x,y;
int id;
};
typedef pair<int,int> pa;
int ord[N],p[N],q[N],x[N],y[N],n,m,A,B,C;
set<pa> res[N];
deque<pi> que[N];
ll dp[N],ans=1e18;
bool cmp(int a,int b){return p[a]<p[b];}
inline db slope(cs pi &a,cs pi &b){
return 1.0*(a.y-b.y)/(1.0*(a.x-b.x));
}
inline void getin(cs int &i,cs int &pos){
//cout<<"getin\n"<<i<<' '<<pos<<'\n';
while(!res[pos].empty()){
pa t=*res[pos].begin();
if(t.fi>p[i])break;
pi now=(pi){t.fi,dp[t.se]+A*t.fi*t.fi-B*t.fi,t.se};
while(que[pos].size()>=2){
pi a=que[pos].back();que[pos].pop_back();
pi b=que[pos].back();
if(slope(b,a)<slope(b,now)){
que[pos].push_back(a);
break;
}
}
//cout<<now.x<<' '<<now.y<<' '<<now.id<<'\n';
que[pos].push_back(now);
res[pos].erase(t);
}
// cout<<"siz: "<<que[pos].size()<<'\n';
}
inline void getout(cs db &slp,cs int &pos){
// cout<<"slp:"<<slp<<'\n';
while(que[pos].size()>=2){
pi a=que[pos].front();que[pos].pop_front();
pi b=que[pos].front();
// cout<<"slope:"<<slope(b,a)<<'\n';
if(slope(b,a)>slp){
que[pos].push_front(a);
return;
}
}
}
signed main(){
// freopen("data.in","r",stdin);
n=in,m=in,A=in,B=in,C=in;
//sf("%d%d%d%d%d",&n,&m,&A,&B,&C);
for(rint i=1;i<=m;++i){
x[i]=in,y[i]=in,p[i]=in,q[i]=in;
//sf("%d%d%d%d",&x[i],&y[i],&p[i],&q[i]);
ord[i]=i;
}
// random_shuffle(ord+1,ord+m+1);
sort(ord+1,ord+m+1,cmp);
que[1].push_back((pi){0,0,0});
for(rint o=1;o<=m;++o){
int i=ord[o];
int pos=x[i];
// cout<<"turn: "<<o<<"\n";
getin(i,pos);
if(que[pos].empty())continue;
db slp=2.0*A*p[i];
getout(slp,pos);
int j=que[pos].front().id;
dp[i]=dp[j]+1ll*A*(p[i]-q[j])*(p[i]-q[j])+1ll*B*(p[i]-q[j])+C;
// cout<<q[i]<<' '<<y[i]<<' '<<dp[q[i]][y[i]]<<'\n';
res[y[i]].insert(make_pair(q[i],i));
if(res[y[i]].size()>50000)getin(i,y[i]);
if(y[i]==n){
ans=min(ans,dp[i]+q[i]);
}
}
cout<<ans;
return 0;
}
```
-----
$O(m*logm)$
```cpp
//O(m*logm)
#include<bits/stdc++.h>
using namespace std;
#define sf scanf
#define pf printf
#define ll long long
#define in red()
#define cs const
#define gc getchar()
#define db double
#define rint register int
#define se second
#define fi first
inline int red(){
int num=0,f=1;char c=gc;
for(;!isdigit(c);c=gc)if(c=='-')f=-1;
for(;isdigit(c);c=gc)num=(num<<1)+(num<<3)+(c^48);
return num*f;
}
cs int N=2e5+10;
struct pi{
ll x,y;
int id;
};
typedef pair<int,int> pa;
int ord[N],p[N],q[N],x[N],y[N],n,m,A,B,C;
set<pa> res[N];
deque<pi> que[N];
ll dp[N],ans=1e18;
bool cmp(int a,int b){return p[a]<p[b];}
inline db slope(cs pi &a,cs pi &b){
return 1.0*(a.y-b.y)/(1.0*(a.x-b.x));
}
inline void getin(cs int &i,cs int &pos){
//cout<<"getin\n"<<i<<' '<<pos<<'\n';
while(!res[pos].empty()){
pa t=*res[pos].begin();
if(t.fi>p[i])break;
pi now=(pi){t.fi,dp[t.se]+A*t.fi*t.fi-B*t.fi,t.se};
while(que[pos].size()>=2){
pi a=que[pos].back();que[pos].pop_back();
pi b=que[pos].back();
if(slope(b,a)<slope(b,now)){
que[pos].push_back(a);
break;
}
}
//cout<<now.x<<' '<<now.y<<' '<<now.id<<'\n';
que[pos].push_back(now);
res[pos].erase(t);
}
// cout<<"siz: "<<que[pos].size()<<'\n';
}
inline void getout(cs db &slp,cs int &pos){
// cout<<"slp:"<<slp<<'\n';
while(que[pos].size()>=2){
pi a=que[pos].front();que[pos].pop_front();
pi b=que[pos].front();
// cout<<"slope:"<<slope(b,a)<<'\n';
if(slope(b,a)>slp){
que[pos].push_front(a);
return;
}
}
}
signed main(){
// freopen("data.in","r",stdin);
n=in,m=in,A=in,B=in,C=in;
//sf("%d%d%d%d%d",&n,&m,&A,&B,&C);
for(rint i=1;i<=m;++i){
x[i]=in,y[i]=in,p[i]=in,q[i]=in;
//sf("%d%d%d%d",&x[i],&y[i],&p[i],&q[i]);
ord[i]=i;
}
// random_shuffle(ord+1,ord+m+1);
sort(ord+1,ord+m+1,cmp);
que[1].push_back((pi){0,0,0});
for(rint o=1;o<=m;++o){
int i=ord[o];
int pos=x[i];
// cout<<"turn: "<<o<<"\n";
getin(i,pos);
if(que[pos].empty())continue;
db slp=2.0*A*p[i];
getout(slp,pos);
int j=que[pos].front().id;
dp[i]=dp[j]+1ll*A*(p[i]-q[j])*(p[i]-q[j])+1ll*B*(p[i]-q[j])+C;
// cout<<q[i]<<' '<<y[i]<<' '<<dp[q[i]][y[i]]<<'\n';
res[y[i]].insert(make_pair(q[i],i));
if(res[y[i]].size()>50000)getin(i,y[i]);
if(y[i]==n){
ans=min(ans,dp[i]+q[i]);
}
}
cout<<ans;
return 0;
}
```