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