|
|
|
@ -967,16 +967,16 @@ int main() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
第一次$dfs$
|
|
|
|
|
**第一次$dfs$**
|
|
|
|
|
|
|
|
|
|
按照换根$dp$的老套路,我们要处理子树里的信息
|
|
|
|
|
|
|
|
|
|
- $g[u]$:以 $u$ 为根的子树中从 $u$ 开始把所有家在这个子树内的人送回家 **并回到** $u$ **节点**的最短路程
|
|
|
|
|
- $f[u]$:以 $u$ 为根的子树中从 $u$ 开始把所有家在这个子树内的人送回家 **并回到** $u$ **节点**的最短路程
|
|
|
|
|
- $sz[u]$:家在以 $u$ 为根的子树中的人数
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
显然,我们可以得到 $\displaystyle g[u]=\sum_{v \in son[u]} g[v]+2\times w_{u \rightarrow v}$,其中$v$是 $u$的子节点,且$sz_v \neq 0$
|
|
|
|
|
显然,我们可以得到 $\displaystyle f[u]=\sum_{v \in son[u]} f[v]+2\times w_{u \rightarrow v}$,其中$v$是 $u$的子节点,且$sz_v \neq 0$
|
|
|
|
|
|
|
|
|
|
其中 $w$ 为边权
|
|
|
|
|
|
|
|
|
@ -999,25 +999,65 @@ int main() {
|
|
|
|
|
先放第一次$dfs$的代码:
|
|
|
|
|
|
|
|
|
|
```cpp {.line-numbers}
|
|
|
|
|
|
|
|
|
|
void dfs1(int u, int fa) {
|
|
|
|
|
if (pos[u]) sz[u] = 1;
|
|
|
|
|
for (int i = h[u]; ~i; i = ne[i]) {
|
|
|
|
|
int v = e[i];
|
|
|
|
|
if (v == fa) continue;
|
|
|
|
|
dfs1(v, u);
|
|
|
|
|
if (sz[v]) {
|
|
|
|
|
f[u] += f[v] + 2 * w[i];
|
|
|
|
|
int now = len[v] + w[i];
|
|
|
|
|
if (now >= len[u])
|
|
|
|
|
slen[u] = len[u], len[u] = now, id[u] = v;
|
|
|
|
|
else if (now > slen[u])
|
|
|
|
|
slen[u] = now;
|
|
|
|
|
}
|
|
|
|
|
dfs1(v, u); // 由底向上,先递归,再更新统计信息
|
|
|
|
|
|
|
|
|
|
// 如果v这个节点,及它的子节点上有人,那么需要汇总统计信息到sz[u]上去
|
|
|
|
|
// 如果v上就没有人,那就不用统计了
|
|
|
|
|
if (sz[v] == 0) continue;
|
|
|
|
|
|
|
|
|
|
// ① u->v,v->u一来一回,路径翻倍 2*w[i]
|
|
|
|
|
// ② 所有子节点都对u有贡献,所以f[u]+
|
|
|
|
|
// ③ 跑完v为根的子树后,v子树的贡献要累加到u子树上,所以f[u]+=f[v]+2*w[i]
|
|
|
|
|
f[u] += f[v] + 2 * w[i];
|
|
|
|
|
|
|
|
|
|
// len[v]:v点出发的最长链长度
|
|
|
|
|
int x = len[v] + w[i];
|
|
|
|
|
|
|
|
|
|
// 更新最长链
|
|
|
|
|
if (x >= len[u])
|
|
|
|
|
slen[u] = len[u], len[u] = x, id[u] = v;
|
|
|
|
|
else if (x > slen[u]) // 更新次长链
|
|
|
|
|
slen[u] = x;
|
|
|
|
|
|
|
|
|
|
// 记录累计人数
|
|
|
|
|
sz[u] += sz[v];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**第二次$dfs$**
|
|
|
|
|
第二次$dfs$我们就要处理全局的事情了
|
|
|
|
|
|
|
|
|
|
令 $g[u]$ 为对于整棵树从 $u$ 开始送人 **最后回到 $u$ 的最短距离**
|
|
|
|
|
|
|
|
|
|
接下来我们就要开始分类了:
|
|
|
|
|
|
|
|
|
|
1、当以 $u$ 为根的子树中没有人的家,即 $sz[u] =0$ 时,我们发现 $g[v]=g[u]+2\times w_{u \rightarrow v}$ ,很好理解,不多说了(画画图就好了
|
|
|
|
|
|
|
|
|
|
2、当除了以$u$ 为根的子树其他地方没有人的家,即 $K−sz[u]=0$时,可以发现 $g[v]=f[v]$
|
|
|
|
|
|
|
|
|
|
3、 其他情况,即$sz[u] \neq 0$ 且 $m-sz[u] \neq 0$时,发现$g[v]=g[u]$
|
|
|
|
|
|
|
|
|
|
那么,更新完 $g$ 之后,我们就要考虑如何更新最长链和次长链了
|
|
|
|
|
|
|
|
|
|
这也是本题最烦的地方了
|
|
|
|
|
|
|
|
|
|
依旧分类讨论,依旧是上面三类(这里编号就代表上面的情况)
|
|
|
|
|
|
|
|
|
|
1、这种情况可以发现 $len[v]=len[u]+w_{u→v}$ ,很简单
|
|
|
|
|
2、这种情况很容易发现完全没有必要更新
|
|
|
|
|
3、最烦的情况来了,这种情况下我们还要分类讨论
|
|
|
|
|
① 当 $len[u]+w≥len$ 且 $id[u] \neq v$ 时,说明 $u$ 的最长链可以更新 $v$ 的最长链,那么直接更新即可
|
|
|
|
|
② 当 $len[u]+w≥len$ 且 $id[u] \neq v$ 时,说明 $u$ 的最长链可以更新 $v$ 的最长链,那么直接更新即可
|
|
|
|
|
③ 当 $len[u]+w≥len$ 且 $id[u] \neq v$ 时,说明 $u$ 的最长链可以更新 $v$ 的最长链,那么直接更新即可
|
|
|
|
|
④ 当 $len[u]+w≥len$ 且 $id[u] \neq v$ 时,说明 $u$ 的最长链可以更新 $v$ 的最长链,那么直接更新即可
|
|
|
|
|
⑤ 当 $len[u]+w≥len$ 且 $id[u] \neq v$ 时,说明 $u$ 的最长链可以更新 $v$ 的最长链,那么直接更新即可
|
|
|
|
|
⑥ 当 $len[u]+w≥len$ 且 $id[u] \neq v$ 时,说明 $u$ 的最长链可以更新 $v$ 的最长链,那么直接更新即可
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
####[$CF708C$ $Centroids$](https://www.luogu.com.cn/problem/CF708C)
|
|
|
|
|