[NOI2019] 回家路线
题意:
给定一张n个点m条边的有向图,每条边代表一趟车,有发车时间$p_i$和到站时间$q_i$。
现在你要从点1坐车到点n,对于一次在点u的换乘,若你在时刻q到达u,在时刻p离开u,则会产生$A(p-q)^{2}+B(p-q)+C$的不满意度。
若你最后在时刻p到达点n还会产生p的不满意度,求从1到n最小的不满意度。
$n\leq 10^{5},m\leq 2\times 10^{5},0\leq p_i < q_i \leq 10^{3}$。
题解:
挺水的一道题,听说场上写个$O(mt)$的分层图最短路就能过?给爷整笑了
显然可以设$dp(i,j)$表示第i个时刻在第j个点的最小不满意度,转移类似于spfa,复杂度$O(m^{2}t)$。
仔细考虑一下发现只有$i=q_k$的状态有用,所以总状态数是$O(m)$的,复杂度$O(m^{2})$。
再考虑一下,这个转移显然是个斜率优化的形式,我们只需要对每个点动态建凸包即可做到$O(m\log{m})$。
显然不能按拓扑序转移(时间混乱),考虑直接按时间转移。
注意到每个状态的dp值都是在一条边上算出来的,于是原图就可以丢掉了。
把每条边挂到$p_i$和$q_i$上,每个dp值在p处算出来,在q处插入凸包。
复杂度$O(m\log{m})$。过掉这题总共花了大概2h,我没希望了
套路:
- 搭车问题:以时间为第一关键字转移。
代码:
#include<bits/stdc++.h> #define maxn 200005 #define maxm 500005 #define inf 0x7fffffff #define ll long long #define rint register ll #define debug(x) cerr<<#x<<": "<<x<<endl #define fgx cerr<<"--------------"<<endl #define dgx cerr<<"=============="<<endl using namespace std; ll n,m,A,B,C; struct node{ll x,y;}; struct edge{ll u,v,p,q,dp;}E[maxm]; vector<ll> vec[maxn]; vector<node> st[maxn]; inline ll read(){ ll x=0,f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } inline void ins(ll u,node c){ while(st[u].size()>1){ ll t=st[u].size()-1; node a=st[u][t-1],b=st[u][t]; if((b.y-a.y)*(c.x-b.x)>=(c.y-b.y)*(b.x-a.x)) st[u].pop_back(); else break; } st[u].push_back(c); } inline node qry(ll u,ll k){ if(!st[u].size()) return (node){-1,-1}; ll l=1,r=st[u].size()-1,res=0; while(l<=r){ ll mid=l+r>>1; node a=st[u][mid-1],b=st[u][mid]; if(b.y-a.y<=(b.x-a.x)*k) res=mid,l=mid+1; else r=mid-1; } return st[u][res]; } inline ll getdp(node a){return a.y-A*a.x*a.x+B*a.x;} int main(){ n=read(),m=read(),A=read(),B=read(),C=read(); for(ll i=1;i<=m;i++){ E[i].u=read(),E[i].v=read(),E[i].p=read(),E[i].q=read(),E[i].dp=1ll<<62; vec[E[i].p].push_back(i),vec[E[i].q].push_back(i); } ins(1,(node){0,0}); ll ans=1ll<<62; for(ll tim=0;tim<=1000;tim++){ if(!vec[tim].size()) continue; for(ll i=0;i<vec[tim].size();i++){ edge e=E[vec[tim][i]]; if(e.q==tim && e.dp!=(1ll<<62)) ins(e.v,(node){e.q,e.dp+A*e.q*e.q-B*e.q}); } for(ll i=0;i<vec[tim].size();i++){ edge e=E[vec[tim][i]]; if(e.p==tim){ node a=qry(e.u,2ll*A*e.p); if(a.x==-1) continue; ll x=e.p-a.x; E[vec[tim][i]].dp=getdp(a)+A*x*x+B*x+C; if(e.v==n) ans=min(ans,E[vec[tim][i]].dp+e.q); } } } printf("%lld\n",ans); return 0; }