一年前,折戟沉沙,后面忘了。
首先我们考虑折半搜索去做这个题。对于 \(x\),在正向的图上跑 Dijkstra,对于 \(y\),在反图上跑 Dijkstra。当两边搜到同一个点的时候,所有的最短路都可以表示成:\(x\to x'\to y'\to y\),其中 \(x'\) 是 \(x\) 已经扩展过的点,\(y'\) 是 \(y\) 已经扩展过的点,结合 Dijkstra 的流程不难说明这个贪心的正确性。
我们发现,在两边碰撞之前,每次扩展的点都是完全独立的,因此如果两边扩展相同的点数,那么相当于每次随机抽一个点出来问什么时候会抽出来一个点两次,由生日悖论容易说明只需要进行 \(O(\sqrt n)\) 次扩展。
因为图是随机的,所以可以认为每个点的期望度数是 \(O(\frac{m}{n})\) 级别的,因此上述过程的复杂度就是 \(O(qmn^{-\frac{1}{2}}\log n)\) 的,可以通过 55p。
我们希望能把 \(m\) 优化掉。首先是 Dijkstra 部分,我们可以先对于每个点的出边按照边权排序,那么对于一个点的出边,肯定是边权小的边先入堆,然后才是边权大的边入堆,因此堆的操作次数就只与点数线性相关了。
这个时候你会发现你已经能过了,第一部分的复杂度被优化到了 \(O(n^{\frac{1}{2}}\log n)\),但是第二部分的复杂度还是 \(O(mn^{-\frac{1}{2}})\),虽然其实 \(O(m^{\frac{3}{4}})\) 的单次询问看上去已经很能过了,但是我们可以做到更好。记 \(dis_{x,y}\) 表示从 \(x\) 走到 \(y\) 的最短路,中间交汇的点为 \(r\),则现在实际上已经有了一个最短路 \(dis_{x,r}+dis_{r,y}\),假设我们现在的最短路是 \(dis_{x,s}+w_{s,t}+dis_{t,y}\),则 \(w_{s,t}\leq 2\max(dis_{x,r}-dis_{x,s},dis_{r,y}-dis_{t,y})\)。如果右侧没有 \(2\) 的系数,那么边数就是前面 Dijkstra 遍历的边数,是 \(O(\sqrt n)\) 级别的,加了这个 \(2\),感性理解一下,也就乘个 \(O(1)\) 倍,因此后面部分的复杂度也就和前面一样了。
但是更慢了怎么会是呢?