洛谷P5468/LOJ3156[NOI2019]回家路线(Dijkstra)
只会$O(mt)$
首先这个题有点,有时间,便套路地想到拆点 (或许我网络流做多了),设最大时间为$t$,那么把每个点拆成$t$个,连上原图的边和等待即可。
恭喜拿到$70pts$
在这个思(bao)路(li)的基础上,我们发现,每个点拆成$t$个是毫无意义的,只要保留所有进出的时间点就可以了,于是总点数从$nt$下降为$2m$,用$dijkstra$复杂度下降到$O(m(t+logn))$,大约$2 \times 10^8$,轻松跑过一点都不虚233
你们说dij死了我偏要用dij
#include<cstdio> #include<algorithm> #include<vector> #include<queue> using namespace std; typedef long long ll; const int N=100050; char rB[1<<21],*S,*T; inline char gc(){return S==T&&(T=(S=rB)+fread(rB,1,1<<21,stdin),S==T)?EOF:*S++;} inline int rd(){ char c=gc(); while(c<48||c>57)c=gc(); int x=c&15; for(c=gc();c>=48&&c<=57;c=gc())x=(x<<3)+(x<<1)+(c&15); return x; } int G[N],p[N<<1],q[N<<1],to[N<<1],nxt[N<<1],n,m,A,B,C; struct node{ int p,t; ll d; bool go; //上一步是坐车则为1,等待则为0 node(){} node(int p,int t,ll d,bool go):p(p),t(t),d(d),go(go){} inline bool operator <(const node &b)const{return d>b.d;} }; priority_queue<node> Q; vector<int> tim[N],tmp; //tim对时刻离散化 vector<vector<int> > id[N]; //记录u结点t时刻出发的边的编号 vector<ll> d[2][N]; int main(){ int i,u; node h; ll ans=0x3f3f3f3f3f3f3f3f; n=rd();m=rd();A=rd();B=rd();C=rd(); for(i=1;i<=m;++i){ u=rd();to[i]=rd();p[i]=rd();q[i]=rd(); nxt[i]=G[u];G[u]=i; } tim[1].push_back(0); for(u=1;u<=n;++u) for(i=G[u];i;i=nxt[i]){ tim[u].push_back(p[i]); tim[to[i]].push_back(q[i]); } for(u=1;u<=n;++u){ sort(tim[u].begin(),tim[u].end()); vector<int>::iterator it=unique(tim[u].begin(),tim[u].end()); tim[u].erase(it,tim[u].end()); //去重 for(i=0;i<tim[u].size();++i){ id[u].push_back(tmp); d[0][u].push_back(ans);d[1][u].push_back(ans); } } for(u=1;u<=n;++u) for(i=G[u];i;i=nxt[i]){ id[u][p[i]=lower_bound(tim[u].begin(),tim[u].end(),p[i])-tim[u].begin()].push_back(i); q[i]=lower_bound(tim[to[i]].begin(),tim[to[i]].end(),q[i])-tim[to[i]].begin(); } Q.push(node(1,0,d[1][1][0]=0ll,1)); while(!Q.empty()){ h=Q.top();Q.pop(); if(d[h.go][u=h.p][h.t]!=h.d)continue; if(h.d>ans)break; //剪枝 if(u==n&&h.d+tim[n][h.t]<ans)ans=h.d+tim[n][h.t]; if(h.go)for(i=h.t;i<tim[u].size();++i)if(h.d+A*(tim[u][i]-tim[u][h.t])*(tim[u][i]-tim[u][h.t])+B*(tim[u][i]-tim[u][h.t])+C<d[0][u][i])Q.push(node(u,i,d[0][u][i]=h.d+A*(tim[u][i]-tim[u][h.t])*(tim[u][i]-tim[u][h.t])+B*(tim[u][i]-tim[u][h.t])+C,0)); //等待 else; else for(i=0;i<id[u][h.t].size();++i)if(h.d<d[1][to[id[u][h.t][i]]][q[id[u][h.t][i]]])Q.push(node(to[id[u][h.t][i]],q[id[u][h.t][i]],d[1][to[id[u][h.t][i]]][q[id[u][h.t][i]]]=h.d,1)); //坐车 } printf("%lld",ans); return 0; }
事实是这个方法相当快,不比正解慢多少?