Travel [BFS]
话说这道题并没有找到提交的地方…就不写代码了[滑稽]
题目描述
给定一张n 个点的完全图,边都是无向的。
一共有n(n−1)/2 条边,其中有m 条边的边权是a,剩下的边边权都是b。
求1 到n 的最短路。
数据范围
2 ≤ n ≤ 100000; 0 ≤ m ≤ 500000
题解
一 初步分析
这是一张完全图,也就是说任意两点之间必有一条路相连。
如果 Len[1−>n]==a L e n [ 1 − > n ] == a ,那么最短路里面肯定不能再包含 a a ,即。
同理可得 Len[1−>n]==b L e n [ 1 − > n ] == b 的情况。
所以最短路一定只包含 a a 或。
现在只用把含 a a 和含的边单独提出来跑最短路,并在两个答案里面取最小值即可。
二 如何跑最短路
对于第一张图(边权全部为 a a 的图),边数并不是很多,时间复杂度内就可以BFS跑完。(dijkstra的时间复杂度是 (n+m)log n ( n + m ) l o g n )
对于第二张图(边权全部为 b b 的图),显然不能够直接用BFS跑。
我们考虑BFS的执行过程:BFS是把队列中的每一个点延伸出去的边依次讨论,并把没在队列中的点加入队中,很多时间浪费在了没有用的边上。实际上,这么多条边里面最多只有条边是有用的,也就是说,每个点只需要入队一次。如果避免了重复进队的点和无用的边,就可以快速找出最短路。
现在的任务是,精确地找出连向最短路的点。
由分析可得,边权为 b b 的边(简称边)最多会被分为 m m 个部分(考虑从一个点辐射状发出的边中,有条 a a 边,剩余的全是边;其余情况同样如此)(当有 a a 边相邻时,边会被分为 <m < m <script type="math/tex" id="MathJax-Element-49">
我们给每条边编号(没有特别的顺序)。
设一个 b b 边的区间为。设 fa[i] f a [ i ] 表示编号>=i,且不在队列中的最小编号。初始时 fa[i]=i f a [ i ] = i ,类似于并查集。注意:这与并查集中 fa[i] f a [ i ] 的定义有所不同。
按照边的编号顺序,对每一个区间进行如下操作:
int x=getfa(L);
while(x<=R){x入队; 进行最短路的操作; fa[x]=x+1; x=getfa(x+1);}
I. fa[x]=x+1是因为x+1尚未入队。
II. 最后一句表示的是x往后跳。精确地找出在最短路上的点。
然后我们就可以愉快地得出第二张图的最短路了。
最后比较两张图的答案,输出最小值。