[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)\) 这条边被经过的情况。

  1. \(f_{u,1,1}'\)
    1. \(v\) 子树已经合法:\(f_{u,1,1}+f_{v,1,0}\)
    2. \(v\) 走出一个人,走到 \(u\) 的子树里,再回到 \(u\)\(f_{v,1,1}+1+f_{u,0,1}\)
    3. \(u\) 走出一个人,走到 \(v\) 的子树里,回到 \(v\),再回到 \(u\)\(f_{u,1,1}+f_{v,0,1}+2\)
  2. \(f_{u,1,0}'\)
    1. \(v\) 子树已经合法:\(f_{u,1,0}+f_{v,1,0}\)
    2. \(v\) 走出一个人,走到 \(u\) 的子树里:\(f_{v,1,1}+1+f_{u,0,0}\),相反有 \(f_{u,1,1}+1+f_{v,0,0}\)
    3. 本来有一条经过 \(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\)
  3. \(f_{u,0,1}'\)
    1. \(v\) 子树已经合法:\(f_{u,0,1}+f_{v,1,0}\)
    2. 未来这条路径先通过 \((u,v)\) 走到 \(v\) 的子树中,再走回来,通过 \((v,u)\) 走到 \(u\) 的子树中,再回到 \(u\)\(f_{u,0,1}+f_{v,0,1}+2\)
  4. \(f_{u,0,0}'\)
    1. \(v\) 子树已经合法:\(f_{u,0,0}+f_{v,1,0}\)
    2. 未来路径先走到 \(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;
}
posted @ 2025-06-19 21:07  XuYueming  阅读(61)  评论(0)    收藏  举报