Tree Pruning
#差分 #树形结构
题目描述
You are given a tree with n n n nodes, rooted at node 1 1 1. In this problem, a leaf is a non-root node with degree 1 1 1. In one operation, you can remove a leaf and the edge adjacent to it (possibly, new leaves appear). What is the minimum number of operations that you have to perform to get a tree, also rooted at node 1 1 1, where all the leaves are at the same distance from the root?
输入格式
Each test contains multiple test cases. The first line contains the number of test cases t t t ( 1 ≤ t ≤ 1 0 4 1 \le t \le 10^4 1≤t≤104). The description of the test cases follows. The first line of each test case contains a single integer n n n ( 3 ≤ n ≤ 5 ⋅ 1 0 5 3 \leq n \leq 5 \cdot 10^5 3≤n≤5⋅105) — the number of nodes. Each of the next n − 1 n-1 n−1 lines contains two integers u u u, v v v ( 1 ≤ u , v ≤ n 1 \leq u, v \leq n 1≤u,v≤n, u ≠ v u \neq v u=v), describing an edge that connects u u u and v v v. It is guaranteed that the given edges form a tree. It is guaranteed that the sum of n n n over all test cases does not exceed 5 ⋅ 1 0 5 5 \cdot 10^5 5⋅105.
输出格式
For each test case, output a single integer: the minimum number of operations needed to achieve your goal.
样例 #1
样例输入 #1
3
7
1 2
1 3
2 4
2 5
4 6
4 7
7
1 2
1 3
1 4
2 5
3 6
5 7
15
12 9
1 6
6 14
9 11
8 7
3 5
13 5
6 10
13 15
13 6
14 12
7 2
8 1
1 4
样例输出 #1
2
2
5
解法
解题思路
对于每一个节点,我们考虑留下它对于答案的贡献,如下图所示,我要考虑留下 2 2 2号节点:
那么 2 2 2号点连着的最链是 2 − 4 − 6 、 2 − 5 2-4-6、2-5 2−4−6、2−5,也就是说留着 2 2 2号点对深度为 d e p t h 2 − d e p t h m a x s o n 2 depth_2-depth_{maxson_2} depth2−depthmaxson2有贡献。 也就是说,分别留着 5 , 4 , 6 5,4,6 5,4,6作为叶子节点的时候,都可以留着 2 2 2号节点,而不需要删除它。
进一步的,所有节点都满足 d e p t h i − d e p t h m a x s o n i depth_i-depth_{maxson_i} depthi−depthmaxsoni有贡献,因此我们就可以对这个深度 + 1 +1 +1,具体而言就是使用差分,然后求一个遍前缀和,最后枚举深度,求出最小需要删除的个数即可,即 a n s = min { a n s , n − d e p t h i } ans = \min\{ans,n - depth_i\} ans=min{ans,n−depthi}
也就是说对于 2 2 2好点,
代码
void solve() {
int n;
std::cin >> n;
std::vector<std::vector<int>>e(n + 1);
for (int i = 1; i <= n - 1; ++i) {
int u, v;
std::cin >> u >> v;
e[u].emplace_back(v);
e[v].emplace_back(u);
}
std::vector<int>deep(n + 1), maxs(n + 1);
auto dfs = [&](auto&&self ,int u, int fa)->void {
deep[u] = deep[fa] + 1;
maxs[u] = deep[u];
for (auto& v : e[u]) {
if (v == fa) continue;
self(self, v, u);
maxs[u] = std::max(maxs[u], maxs[v]);
}
};
dfs(dfs, 1, 1);
int maxd = *std::max_element(deep.begin() + 1, deep.end());
std::vector<int>d(n + 2);
for (int i = 1; i <= n; ++i) {
d[deep[i]]++;
d[maxs[i] + 1]--;
}
std::partial_sum(d.begin() + 1, d.end(), d.begin() + 1);
std::vector<int>prefix(n + 1);
int res = n - *std::max_element(d.begin() + 1, d.end());
std::cout << res << "\n";
}
signed main() {
std::ios::sync_with_stdio(0);
std::cin.tie(0);
std::cout.tie(0);
int t = 1;
std::cin >> t;
while (t--) {
solve();
}
};