Search for a command to run...
Progressive hints first, then the full explanation and implementation when you're ready to cash out.
Review status
AI-generated and still unreviewed. Double-check the details before internalizing them.
Hints
Open only as much as you need to keep the solve alive.
Forget the actual pairing for a second. A pair contributes to every edge on the path between and , so the total answer can be rewritten as a sum over edges.
Root the tree. For an edge from a parent to a child , let be the number of original leaves in the subtree of . If you must pair an even number of leaves, what parity must the number of pairs crossing that edge have?
Inside a subtree, leaves paired internally disappear in twos. So for an even-size selected set, edge must be crossed at least times. A bottom-up greedy pairing shows this lower bound is tight: the edge is crossed exactly once iff is odd.
If the total number of original leaves is odd, exactly one leaf stays unmatched. Pretend you choose that leaf first and remove it from the set. Then you are back to the even case on .
Compute for all rooted subtrees and let If the total number of leaves is even, the answer is just . If it is odd and you remove leaf , then every edge on the root-to- path flips parity: odd even gives , even odd gives . So One DFS for , one DFS for these path sums, done.
This looks like some nasty matching problem on leaves. On a general graph, sure, that would suck. But on a tree, every pair is just a path.
If is the number of chosen pairs whose path uses edge , then
So the whole game is: for each edge, how many pairs are forced to cross it?
Fix any root . For every non-root vertex , let be the number of original leaves in the subtree of .
Look at the edge between and its parent. Suppose all leaves must be paired.
Let be the number of pairs with exactly one endpoint inside the subtree of . After those leaves leave the subtree, every remaining leaf inside it must be paired internally. That means
So
hence in particular
That is a lower bound for each edge.
Now the nice part: it is tight.
Do a bottom-up greedy process:
So each subtree sends at most one leaf through its parent edge, and it does so exactly when its leaf count is odd. Therefore the minimum cost for an even number of leaves is
Yep. Just parity. The scary matching was mostly fake news.
If the total number of leaves is odd, exactly one original leaf stays unmatched. Suppose that leaf is .
Then we remove from consideration and pair all leaves in . That set has even size, so the previous formula applies.
For a vertex , the new number of leaves in its subtree becomes:
So the cost for leaving unmatched is
where is iff is in the subtree of .
Now comes the key simplification.
The vertices whose subtree contains are exactly the vertices on the root-to- path, excluding the root. So only those edges change.
Let
For a vertex on the root-to- path:
So
Therefore, when the total number of leaves is odd, we just need the minimum root-to-leaf path sum with edge weight
That is for even , and for odd .
Root the tree at vertex .
deg[u] <= 1.pref[1] = 0to of v,
Then
Each edge is processed a constant number of times.
So each test case runs in
and over all test cases the total complexity is
with memory.
Clean, fast, and no cursed heavy DP tables. Just parity doing parity things.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
vector<vector<int>> g(n + 1);
vector<int> deg(n + 1, 0);
for (int i = 0; i < n - 1; ++i) {
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
deg[u]++;
deg[v]++;
}
int root = 1;
vector<int> parent(n + 1, -1), order;
order.reserve(n);
parent[root] = 0;
order.push_back(root);
for (int i = 0; i < (int)order.size(); ++i) {
int u = order[i];
for (int v : g[u]) {
if (v == parent[u]) continue;
parent[v] = u;
order.push_back(v);
}
}
vector<int> leaf(n + 1, 0);
for (int u = 1; u <= n; ++u) {
leaf[u] = (deg[u] <= 1);
}
vector<int> cnt(n + 1, 0);
ll base = 0;
for (int i = n - 1; i >= 0; --i) {
int u = order[i];
cnt[u] = leaf[u];
for (int v : g[u]) {
if (v == parent[u]) continue;
cnt[u] += cnt[v];
}
if (u != root) base += (cnt[u] & 1);
}
int totalLeaves = cnt[root];
if ((totalLeaves & 1) == 0) {
cout << base << '\n';
continue;
}
vector<ll> pref(n + 1, 0);
ll best = (ll)4e18;
for (int u : order) {
if (leaf[u]) best = min(best, pref[u]);
for (int v : g[u]) {
if (v == parent[u]) continue;
pref[v] = pref[u] + ((cnt[v] & 1) ? -1LL : 1LL);
}
}
cout << base + best << '\n';
}
return 0;
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
vector<vector<int>> g(n + 1);
vector<int> deg(n + 1, 0);
for (int i = 0; i < n - 1; ++i) {
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
deg[u]++;
deg[v]++;
}
int root = 1;
vector<int> parent(n + 1, -1), order;
order.reserve(n);
parent[root] = 0;
order.push_back(root);
for (int i = 0; i < (int)order.size(); ++i) {
int u = order[i];
for (int v : g[u]) {
if (v == parent[u]) continue;
parent[v] = u;
order.push_back(v);
}
}
vector<int> leaf(n + 1, 0);
for (int u = 1; u <= n; ++u) {
leaf[u] = (deg[u] <= 1);
}
vector<int> cnt(n + 1, 0);
ll base = 0;
for (int i = n - 1; i >= 0; --i) {
int u = order[i];
cnt[u] = leaf[u];
for (int v : g[u]) {
if (v == parent[u]) continue;
cnt[u] += cnt[v];
}
if (u != root) base += (cnt[u] & 1);
}
int totalLeaves = cnt[root];
if ((totalLeaves & 1) == 0) {
cout << base << '\n';
continue;
}
vector<ll> pref(n + 1, 0);
ll best = (ll)4e18;
for (int u : order) {
if (leaf[u]) best = min(best, pref[u]);
for (int v : g[u]) {
if (v == parent[u]) continue;
pref[v] = pref[u] + ((cnt[v] & 1) ? -1LL : 1LL);
}
}
cout << base + best << '\n';
}
return 0;
}