这题不是裸的最短路么?但是一看数据范围就傻了。点数10^6,边数10^7。这个spfa就别想了(本来spfa就是相当不靠谱的玩意),看来是要用堆优化dijkstra了。但是,平时写dijkstra时为了偷懒直接用的STL的priority_queue,没办法改变权值,所以都是直接把pair压进堆里。然后时间复杂度O(mlogm),空间复杂度O(m),不靠谱。手写二叉堆?改变权值是O(logn)的,所以时间复杂度O(mlogn),空间复杂度O(n),还是要T。看来是需要一种比较牛逼的堆了。
Fibonacci堆就很牛逼,但是难写难调(算导上都说它“编码复杂度高”、“实践价值不大”、“价值主要在学术方面”。所以我学习了一下它的一个好写好调的替代品:Pairing Heap。它的结构其实就是堆有序的树。下面简单说一下它的几种操作(假定为小根堆)。
- findMin() 直接返回树根
- merge(a, b) 把权值较大的挂在权值较小的下面作为子女
- decreaseKey(a, v) 如果a是根节点,则不改变形态,否则断开a和a的父节点,将两树进行merge
- deleteMin() 将根节点删掉,然后将子节点从左到右(最左端为最近加入)分对合并,再将合并后的树从右向左合并。
- delete(a) 执行decreaseKey(a, –oo),然后执行deleteMin()
论文中说除了删除操作为均摊O(logn)的以外其他的都是均摊O(1)(我只弄懂了论文中写的均摊O(sqrt(n))的上界),于是这对于dijkstra优化就有帮助了。因为对每条边都要执行一次decreaseKey,所以decreaseKey从O(logn)优化为O(1)是相当有效的。现在,总复杂度为O(nlogn+m),就可以通过题目了。
BZOJ3040 最短路 (堆优化dijkstra)
时间: 2024-11-02 23:29:30