传送门。
$\texttt{Description}$
$n$ 个点的树,$m$ 个人。第 $i$ 个人的散步路径是从 $x_i$ 到 $y_i$。
一个人高兴当且仅当它获得了一个宠物或 $x_i$ 到 $y_i$ 每一条边上都有一个宠物。
问最少分发多少个宠物才能使所有居民高兴。
输出方案。
$1\le n\le 10^4$,$1\le m\le 2\times 10^4$。
$\texttt{Solution}$
思路三分钟,代码三小时。纪念一下 $\texttt{700 AC}$。
前置知识:网络流,线段树优化建图,树链剖分。
考虑一个显然的二分图。
所有人在左边,树上的边在右边。
对于一个人来说,要么给人宠物,要么给路径上所有边宠物。肯定不会同时给,这样就不满足最优了。
这就是很模板的最小割的模型了。
建图方式:
- $s$ 向每一个人连一条流量为 $1$ 的边。
- 每一个人向路径上的每一条边连流量为 $\infty$ 的边。
- 最后树上每一条边向 $t$ 连流量 $1$ 的边。
稍微解释一下,$\infty$ 表示只能选一个,因为最小割不可能割掉 $\infty$ 的边。流量为 $1$ 是因为分发了一个宠物。
这样建图边数是 $nm$ 的。很容易想到线段树优化建图。
但是这是在树上,没关系,我们通过树链剖分,将一条路径分成若干个连续的区间,然后再用线段树优化建图就可以了。
问题在于输出方案。
先考虑第一行。
如果 $s$ 到某一个人的流量是 $0$,是不是说明,这个人被选取了,毕竟流量为 $0$ 了。
然后考虑树上某条边 $e$ 连到 $t$ 的一条边,有一条残余网络通向了 $e$,这么说明 $e$ 到 $t$ 的流量肯定为 $0$ 了,因为如果不是 $0$ 就又形成了一条增广路。
所以我们进行一遍 $\texttt{dfs}$ 来找到选取了哪些边。
但是注意,我们找到的所谓的“边”,只是在线段数中的节点编号,我们还需要一个数组映射出某个叶子节点编号对应维护的点,然后对应维护的点在映射出原树中的点,最后对于原树中国每一个点再维护它属于哪一个人(这个可以用 $\texttt{map}$ 来维护)。
代码巨难写:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include