[IOI2016]railroad
题面
有 \(n\) 个二元组,第 \(i\) 个为 \(a_i,b_i\) 。
对于一个 \(1\sim n\) 的排列 \(p\),定义其权值为:
求出最小权值排列的权值。
数据范围 :\(n\le 2\times 10^5\) 。
题解
先加入一个 \((\inf,0)\) 的点,然后把排列改为环(也就是 \(p_1\) 和 \(p_n\) 也要计算贡献)。
然后就是一个很神奇的转换:
我们可以把权值离散化之后看成点,\(i\) 与 \(i+1\) 之间有边,正向走 \(i\rightarrow i+1\) 边权 \(0\) ,反向走 \(i+1\rightarrow i\) 边权为相邻权值的差,然后把一个二元组看做一个必须要走的边,然后在这个图上走一个最短欧拉回路就是答案。
为什么?
你可以把当前在的点看作是一个参数,选一个二元组看做把当前的 \(a_i\) 强制转换为 \(b_i\) ,然后在两个二元组之间的改变参数所需要的代价就是权值计算公式。
所以现在的问题就是解决这个最短欧拉回路问题了。
不知道这是不是一个经典问题...
因为我们有一些必走边,我们可以最开始认为走了这些边,然后用两点之间的边去把这些边连为一条路径。
既然是一个欧拉回路,那么对于一个必走边 \(a_i\rightarrow b_i\) ,一定要走一次回来的路。
那么对于一个边 \(i,i+1\) ,如果覆盖了这条边的向左的 必选边 和向右的 必选边 数量不一致,那么就一定需要向左/向右走,加上对应的代价就行。
做完这个操作之后我们会得到若干个存在欧拉回路的联通块,但是原图还没有欧拉回路。我们还需要把联通块连起来,这个操作每次要连一条先右的和一条向左的。
显然我们只会在相邻的联通块之间连边,否则一定不优,扫一遍加边,然后跑最小生成树即可。
扩展
如果贡献改为:
那么我们就不用加入新的二元组,把正向走 \(i\rightarrow i+1\) 边权也改为权值之差就行。
启发
- 对于一系列排列权值的问题都可以这么做,只要权值计算方式是线性的。
- 后面的欧拉回路问题也是很巧妙的题。