本文已在博客园同步发布。

注意此为个人题解,并非转载于洛谷。

[PA 2012 Finals] Tax

题目大意

给定一个 \(n\) 个点 \(m\) 条边的无向图,定义路径的代价如下:

经过一个中间点时,代价为 \(max(\) 进入该点的边权, 离开该点的边权 \()\)。
起点 \(1\) 的代价为离开起点的边权
终点 \(n\) 的代价为进入终点的边权
求从点 \(1\) 到点 \(n\) 的最小代价。

数据范围: \(n\le10^5,m\le2\times10^5,1\le c\le10^6,n\le10^5,m\le2\times10^5,1\le c\le10^6\)

算法分析

这道题与普通最短路最大的不同在于:代价不是边权之和,而是相邻两条边权取 后再求和。也就是说,代价取决于边的组合而非单条边。

这导致我们无法直接在原图上跑 Dijkstra,因为到达同一个点时,从哪条边进来会影响后续的代价计算,状态不能简单合并。

化边为点

既然代价取决于边的组合,一个自然的想法是:把原图的每条边看作新图的一个点,两条边如果在原图中首尾相连(即存在公共端点),就在新图中连边,边权为两条边权值的 。

具体操作:

1. 将每条无向边 \(u,v,w\) 拆成两条有向边:\(u\rightarrow v\) 和 \(v\rightarrow u\)。

2. 对于原图中两条有向边 \(a:u\rightarrow v\) 和 \(b:v\rightarrow u\)(\(a\) 的终点 \(b\) 的起点),在新图中从点 \(a\) 向点 \(b\) 连一条有向边,权值为 \(max(a_w,b_w)\)。

3. 新建超级源点 \(S\):从 \(S\) 向所有从点 \(1\) 出发的有向边连边,权值为该边的边权(起点代价)。

4. 新建超级汇点 \(T\):从所有指向点 \(n\) 的有向边向 \(T\) 连边,权值为该边的边权(终点代价)。

5. 在新图上跑 \(S\rightarrow T\) 的最短路即为答案。

但是给你个菊花图那你不就炸了。

差分优化建图

我们需要把每个点周围的边压缩到原来的一半。

核心观察: 对于原图某个点 \(v\),设其所有出边按边权从小到大排序为 \(e_1,e_2,…,e_k\)(权值分别为 \(1_w\le 2_w\le⋯\le k_w\))。

若从边 \(e_i\) 进入 \(v\),从边 \(e_j\)​ 离开 \(v\)(\(i\le j\)),则代价为 \(max⁡(i_w,j_w)=j_w\)。这个值可以拆解为:

\(j_w=i_w+(i_w+1−i_w)+(i_w+2−i_w+1)+⋯+(j_w−j_w−1)\)

建图方法: 对每个点 \(v\) 的所有出边按权值排序后:

相邻两条边 \(e_i\rightarrow e_i+1\)​ 连一条有向边,权值为 \(wi+1−wi\)(正向差分边)。
相邻两条边 \(e_i+1\rightarrow e_i\)​ 连一条有向边,权值为 \(0\)(反向零权边)。
对于每条有向边 \(u\rightarrow v\)(权值 \(w\)),从其反向边 \(v\rightarrow u\) 向 \(u\rightarrow v\) 连一条权值为 \(w\) 的边(表示进入该点时需要支付的基础代价)。
为什么这样是对的?

假设从边 \(p\) (权值 \(p_w\)​ )进入点 \(v\),要从边 \(q\)(权值 \(q_w\))离开:

若 \(p_w\le q_w\): 先从反向边走到 \(p\) (代价 \(p_w\)​ ),然后沿着正向差分边一路走到 \(q\),总代价 \(=p_w+(q_w−p_w)=q_w=max⁡(p_w,q_w)\)。
若 \(p_w>q_w\): 先从反向边走到 \(p\) (代价 \(p_w\)​ ),然后沿着反向零权边走到 \(q\),总代价 \(=p_w+0=p_w=max⁡(p_w,q_w)\)。
这样,每个点周围的边数降了一半,总边数为 \(O(m)\) 级别。

再跑一遍最短路就没啦!

时间复杂度分析

前面都说完了也没啥好说的了。

后记

不要像作者一样懒,\(w_a\) 打成 \(a_w\) 干脆后面就照样写算了。