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.
After a move, forget how the older paths were grouped. Let be the forest of unused edges and let be the set of vertices on the most recently chosen path. Try classifying the position using only the parities of for vertices .
Conjecture that the next player loses exactly when every vertex of has even degree in . Indeed, any legal path has an endpoint ; deleting the path removes exactly one edge at , so the opponent receives a path containing an odd-degree vertex.
For the reverse direction, suppose some has odd degree in . Its connected component contains another odd-degree vertex . Choose the closest such : every strict internal vertex of the - path has even degree. Removing this path makes the remaining degree of every vertex on it even, proving the parity characterization.
Apply that characterization to Tom's first path. Each endpoint loses one incident edge, while each strict internal vertex loses two. Therefore, Tom's path is winning exactly when both endpoints have odd degree in the original tree and every strict internal vertex has even degree.
Look at the forest induced by the even-degree vertices. If one of its components has incident edges leading to odd-degree vertices, every unordered pair of those boundary edges gives one winning path of length at least two, contributing . Separately add every edge whose two endpoints both have odd degree. An iterative DFS or DSU counts all of this in linear time.
The enormous-looking game tree is bait. Once we describe a position correctly, the whole game collapses to degree parity.
After at least one path has been chosen, define:
A legal next path must lie entirely in and have at least one endpoint in . Older paths matter only because their edges have disappeared.
Call the position even if
for every .
Lemma. The player to move loses exactly in the even positions.
Take any legal path . One of its endpoints, say , belongs to . Because is an endpoint of , deleting removes exactly one unused edge incident to .
Its degree therefore changes from even to odd. Also, lies on , which becomes the active path for the opponent. Hence the opponent's position is not even.
Suppose some has odd degree in . In any connected component, the number of odd-degree vertices is even, so the component of contains another odd-degree vertex.
Choose the closest such vertex . On the unique path from to , every strict internal vertex has even degree in : an odd internal vertex would be closer to than was.
Choose this - path as the move. It is legal because . After removing it:
Thus every vertex of the newly chosen path has even remaining degree. The opponent receives an even position.
Every move removes at least one edge, so the game is finite. The two transition properties above prove the lemma: even positions are losing, and non-even positions are winning. No giant minimax DP required; parity already did the dirty work.
Let Tom's first path be , and let be the degree of in the original tree. Jerry then plays on the forest obtained after deleting the edges of .
For a vertex on :
By the lemma, Tom wins precisely when Jerry receives an even position. Therefore:
A first path is winning if and only if both endpoints have odd original degree and every strict internal vertex has even original degree.
This also handles a one-edge path: it has two endpoints and no internal vertices, so it wins exactly when both endpoint degrees are odd.
Consider the induced forest consisting only of vertices whose original degree is even. Let its connected components be .
For one component , let be the number of edges with one endpoint in and the other endpoint an odd-degree vertex.
Choose any two such boundary edges. Their odd endpoints, together with the unique route through , form a path whose endpoints are odd and whose internal vertices are all even. Hence it is winning.
Conversely, every winning path of length at least two has at least one internal vertex. All its internal vertices are even and connected, so they lie in exactly one component . The first and last edges of the path are then exactly two boundary edges of that component. This gives a bijection, so component contributes
Because the input is a tree, the same odd vertex cannot have two edges into one even component: those two edges plus the route inside the component would create a cycle. Thus each selected pair really has two distinct endpoints.
Winning paths of length one contain no even internal component, so count them separately. They are precisely the edges joining two odd-degree vertices.
The final formula is
Build the adjacency list and all degrees. Traverse every connected component induced by even-degree vertices using an iterative DFS. While visiting a component, count every adjacent odd-degree vertex as one boundary edge, then add .
Finally, scan every tree edge once and add one whenever both endpoints have odd degree.
The answer can be quadratic in , so it must use long long.
The parity lemma proves that Tom wins after choosing exactly those paths with odd endpoints and even strict internal vertices. Every such path of length at least two corresponds uniquely to a pair of boundary edges of one even-vertex component, while every winning one-edge path is an odd-odd edge. The algorithm counts both disjoint cases exactly once, so its output is the required number of winning first moves.
Each vertex and edge is processed only a constant number of times.
#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);
vector<int> degree(n);
for (int i = 0; i < n - 1; ++i) {
int u, v;
cin >> u >> v;
--u;
--v;
g[u].push_back(v);
g[v].push_back(u);
++degree[u];
++degree[v];
}
ll answer = 0;
vector<char> seen(n);
vector<int> stk;
stk.reserve(n);
for (int start = 0; start < n; ++start) {
if (seen[start] || (degree[start] & 1)) continue;
ll boundary = 0;
seen[start] = true;
stk.push_back(start);
while (!stk.empty()) {
int u = stk.back();
stk.pop_back();
for (int v : g[u]) {
if (degree[v] & 1) {
++boundary;
} else if (!seen[v]) {
seen[v] = true;
stk.push_back(v);
}
}
}
answer += boundary * (boundary - 1) / 2;
}
for (int u = 0; u < n; ++u) {
for (int v : g[u]) {
if (u < v && (degree[u] & 1) && (degree[v] & 1)) {
++answer;
}
}
}
cout << answer << '\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);
vector<int> degree(n);
for (int i = 0; i < n - 1; ++i) {
int u, v;
cin >> u >> v;
--u;
--v;
g[u].push_back(v);
g[v].push_back(u);
++degree[u];
++degree[v];
}
ll answer = 0;
vector<char> seen(n);
vector<int> stk;
stk.reserve(n);
for (int start = 0; start < n; ++start) {
if (seen[start] || (degree[start] & 1)) continue;
ll boundary = 0;
seen[start] = true;
stk.push_back(start);
while (!stk.empty()) {
int u = stk.back();
stk.pop_back();
for (int v : g[u]) {
if (degree[v] & 1) {
++boundary;
} else if (!seen[v]) {
seen[v] = true;
stk.push_back(v);
}
}
}
answer += boundary * (boundary - 1) / 2;
}
for (int u = 0; u < n; ++u) {
for (int v : g[u]) {
if (u < v && (degree[u] & 1) && (degree[v] & 1)) {
++answer;
}
}
}
cout << answer << '\n';
}
return 0;
}