【堆模拟费用流增广】UOJ455 [UER #8] 雪灾与外卖
【题目】
原题地址
一条直线上有 n n n个送餐员和 m m m个餐厅。每个送餐员都要去餐厅取菜,花费为距离+菜的价值。每个餐厅有提供菜数量限制,求最小花费。 n , m ≤ 1 0 5 n,m\leq 10^5 n,m≤105,其他数字 ≤ 1 0 9 \leq 10^9 ≤109
【解题思路】
题解看这
设送餐员为 a a a,餐厅为 b b b,坐标为 x x x。
首先我们可以观察到一个十分 naive \text{naive} naive的性质: ? 1 ≤ a i <
a j ≤ n , 1 ≤ b k <
b l ≤ m , ∣ x a i ? x b k ∣ + ∣ x a j ? x b l ∣ ≤ ∣ x a j ? x b k ∣ + ∣ x a i ? x b l ∣ \forall 1\leq a_i<
a_j\leq n,1\leq b_k<
b_l\leq m,|x_{a_i}-x_{b_k}|+|x_{a_j}-x_{b_l}|\leq |x_{a_j}-x_{b_k}|+|x_{a_i}-x_{b_l}| ?1≤ai?
考虑一个更显然的问题,这个就是一个二分图匹配问题,我们建图跑费用流就可以了。
然而这样做并不优秀,于是我们考虑套路,用堆或线段树来模拟费用流的增广,这里显然是用堆。
我们考虑把餐厅和送餐员放在一起按照坐标排序,从前往后考虑,当考虑到一名送餐员 i i i时,我们先让它与前面的一个空的餐厅 j j j匹配。费用为 x i ? x j x_i-x_j xi??xj?,那么我们就是要找一个最小的 ? y j -y_j ?yj?。(如果没有空的餐厅我们可以视为在 ? ∞ -\infty ?∞处有无穷个餐馆)。
匹配完之后,我们可能进行调整,把这名送餐员改为匹配后面的餐厅。那么我们就可以撤销这次操作,然后把这名送餐员当做没有使用过,那么往堆中丢入 ? ( x i ? x j ) ? x i -(x_i-x_j)-x_i ?(xi??xj?)?xi?,即减去之前这组匹配的贡献,然后寻找新匹配。 扫到餐厅时也类似,先可以匹配一名送餐员,然后可以撤销这组匹配,寻找新匹配。
对所有餐厅和送餐员分别建一个堆来维护这个操作。注意我们既可以对送餐员进行反悔,也可以对餐厅进行反悔,即每新增一组匹配,我们往两个堆中分别加入反悔操作。
设每个餐厅能提供 c i c_i ci?的菜,复杂度是O ( ( n + ∑ c i ) log ? ( n + ∑ c i ) ) ((n+\sum c_i)\log (n+\sum c_i)) ((n+∑ci?)log(n+∑ci?))
这个就是一个纯模拟费用流了。
考虑这个过程中我们维护了两个堆,一个维护待匹配的送餐员,一个维护待匹配的餐厅。之前复杂度不对的原因是送餐员堆的复杂度没有保证,因为一个餐厅匹配了一名送餐员之后,这名送餐员可能反悔,所以这名送餐员又会重新丢入送餐员堆中。
但注意到对于送餐员 x , y x,y x,y和餐厅 a , b a,b a,b来说,若 x <
y <
a <
b x<
y<
a<
b x
【【堆模拟费用流增广】UOJ455 [UER #8] 雪灾与外卖】【参考代码】
#include
推荐阅读
- 宽容谁
- 我要做大厨
- 增长黑客的海盗法则
- 画画吗()
- 2019-02-13——今天谈梦想()
- 远去的风筝
- 三十年后的广场舞大爷
- 叙述作文
- 20190302|20190302 复盘翻盘
- 学无止境,人生还很长