Roads and Gates
来源:AT_abc463_e
难度:1055
这场 D 和 E 自己做的方法好麻烦,导致没时间做 F 和 G。
提供一个别于建两个虚点的思路。对于特殊边而言,若真的建出 21n(n−1) 条双向边,发现边数会爆炸。所以不可行。
考虑一下将 21n(n−1) 条边不直接建出来,显然这之中大部分边是没用的。注意到 wi,j=xi+Y+xj,观察 Dijkstra 的过程,对于已经找到最小值的点集 S,和尚未找到最小值的点集 T,显然有 S∩T=∅,S∪T=V,下一个更新 dis 的点必然是由 S 中某一点 u 所连一条边的另外一个端点 v,且 v∈T。实际上,对于特殊边,也是一样的。考虑 Dijkstra 堆优化每一次实际是把 dis 最小的点拿出来,对于 xu+Y 的部分只要找到 S 的某一个点使其最小即可,xv 的部分同理,那么我们在 Dijkstra 贪心过程中,每当 S 发生变化,即找到一个点 u 的 dis 确定了,可以把这条没有建出来的边扔到堆里,实际上只会新增 n−1 条虚边。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| void dijkstra(int S){ memset(dis,0x3f,sizeof dis); memset(vis,0,sizeof vis); priority_queue<pli>q; dis[S]=0; q.push(mkp(-dis[S],S)); ll minn=x[1]; while(!q.empty()){ int u=q.top().se; q.pop(); if(vis[u])continue; vis[u]=1; Min(minn,dis[u]+x[u]); s.erase(mkp(x[u],u)); for(auto it:E[u]){ int v=it.v,w=it.w; if(dis[v]>dis[u]+w){ dis[v]=dis[u]+w; q.push(mkp(-dis[v],v)); } } if(!s.empty()){ auto it=*s.begin(); int v=it.se; if(dis[v]>minn+y+x[v]){ dis[v]=minn+y+x[v]; q.push(mkp(-dis[v],v)); } } } }
|