[POI 2021/2022 R2] age 题解
前言
题目链接:洛谷。
题意简述
\(n\) 个结点的树,有 \(k\) 个人,初始在不同的结点。安排一种行走方式,使得所有结点均被到达过,并且不会有一个结点被不同的两个人经过(同一个结点可以被同一个人经过多次)。你需要最小化所有人行走的距离和。
\(1\leq k\leq n\leq5\times10^5\)。
题目分析
显然是树形 DP,对 \(u\) 被哪个人经过分类讨论,结合做题经验,不难得到状态 \(f_{u,0/1,0/1}\) 表示 \(u\) 子树,未来子树外一个人走到 \(u\),还是 \(u\) 已经被其子树里某个人经过,操作完 \(u\) 子树后要不要走回 \(u\),的答案。答案即为根的 \(f_{u,1,0}\)。
考虑一个一个合并儿子子树的过程。
DP 初始值对 \(u\) 是否初始有人讨论。若有人,除 \(f_{u,1,0/1}=0\) 外均为 \(\infty\),否则除 \(f_{u,0,0/1}=0\) 外均为 \(\infty\)。
合并进 \(v\) 的子树,考虑 \((u,v)\) 这条边被经过的情况。
- \(f_{u,1,1}'\):
- \(v\) 子树已经合法:\(f_{u,1,1}+f_{v,1,0}\);
- \(v\) 走出一个人,走到 \(u\) 的子树里,再回到 \(u\):\(f_{v,1,1}+1+f_{u,0,1}\);
- \(u\) 走出一个人,走到 \(v\) 的子树里,回到 \(v\),再回到 \(u\):\(f_{u,1,1}+f_{v,0,1}+2\);
- \(f_{u,1,0}'\):
- \(v\) 子树已经合法:\(f_{u,1,0}+f_{v,1,0}\);
- \(v\) 走出一个人,走到 \(u\) 的子树里:\(f_{v,1,1}+1+f_{u,0,0}\),相反有 \(f_{u,1,1}+1+f_{v,0,0}\);
- 本来有一条经过 \(v\) 的路径,现在略微修改,当人走到 \(v\) 的时候,先走到 \(u\),走进 \(u\) 的子树再回到 \(u\),走到 \(v\),继续 \(v\) 本来的路径:\(f_{v,1,0}+f_{u,0,1}+2\),相反有 \(f_{u,1,0}+f_{v,0,1}+2\);
- \(f_{u,0,1}'\):
- \(v\) 子树已经合法:\(f_{u,0,1}+f_{v,1,0}\);
- 未来这条路径先通过 \((u,v)\) 走到 \(v\) 的子树中,再走回来,通过 \((v,u)\) 走到 \(u\) 的子树中,再回到 \(u\):\(f_{u,0,1}+f_{v,0,1}+2\);
- \(f_{u,0,0}'\):
- \(v\) 子树已经合法:\(f_{u,0,0}+f_{v,1,0}\);
- 未来路径先走到 \(v\) 子树中,再回来,再往 \(u\) 子树中走:\(f_{u,0,0}+f_{v,0,1}+2\),相反有 \(f_{v,0,0}+f_{u,0,1}+1\),这里不再是 \(+2\) 了,因为 \((u,v)\) 只被经过了一次;
问题解决了,时间复杂度 \(\mathcal{O}(n)\)。
代码
#include <cstdio>
#include <vector>
#include <cstring>
using ll = long long;
const int N = 5e5 + 10;
int n, k;
std::vector<int> e[N];
bool mark[N];
const ll inf = 0x3f3f3f3f3f3f3f3f;
ll f[N][2][2];
inline void O(ll &a, ll b) {
a = b < a ? b : a;
}
void dfs(int u, int fa) {
memset(f[u], 0x3f, sizeof(f[u]));
if (mark[u]) {
f[u][1][0] = 0;
f[u][1][1] = 0;
} else {
f[u][0][0] = 0;
f[u][0][1] = 0;
}
for (int v : e[u])
if (v != fa) {
dfs(v, u);
ll t[2][2];
memset(t, 0x3f, sizeof(t));
O(t[1][1], f[u][1][1] + f[v][1][0]);
O(t[1][1], f[u][0][1] + f[v][1][1] + 1);
O(t[1][1], f[u][1][1] + f[v][0][1] + 2);
O(t[1][0], f[u][1][0] + f[v][1][0]);
O(t[1][0], f[u][0][0] + f[v][1][1] + 1);
O(t[1][0], f[u][1][1] + f[v][0][0] + 1);
O(t[1][0], f[u][0][1] + f[v][1][0] + 2);
O(t[1][0], f[u][1][0] + f[v][0][1] + 2);
O(t[0][1], f[u][0][1] + f[v][1][0]);
O(t[0][1], f[u][0][1] + f[v][0][1] + 2);
O(t[0][0], f[u][0][0] + f[v][1][0]);
O(t[0][0], f[u][0][0] + f[v][0][1] + 2);
O(t[0][0], f[u][0][1] + f[v][0][0] + 1);
memcpy(f[u], t, sizeof(t));
}
}
signed main() {
scanf("%d%d", &n, &k);
for (int i = 1, u; i <= k; ++i) {
scanf("%d", &u);
mark[u] = true;
}
for (int i = 1, u, v; i < n; ++i) {
scanf("%d%d", &u, &v);
e[u].emplace_back(v);
e[v].emplace_back(u);
}
dfs(1, 0);
printf("%lld", f[1][1][0]);
return 0;
}
本文作者:XuYueming,转载请注明原文链接:https://www.cnblogs.com/XuYueming/p/18937129。
若未作特殊说明,本作品采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可。

浙公网安备 33010602011771号