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.
For one fixed starting vertex , look at paths of length . Since every such path must be alternating, what direction must every edge incident to have?
If is beautiful, all edges touching must point out of . Now take any neighbor and extend to paths . That forces all edges touching to point into .
The forced role alternates by distance from : even-distance vertices must have all incident edges outgoing, odd-distance vertices must have all incident edges incoming.
An edge between two vertices with the same distance parity would need to be oriented two opposite-impossible ways. So a beautiful vertex can only exist inside a bipartite connected component.
For each connected component: if it is bipartite, orient all edges from one color class to the other and choose the larger side as beautiful. If it is not bipartite, it contributes .
Research summary: I checked the official Codeforces problem/editorial material and an external CF Step explanation/code page first. The official editorial page currently exposes the accepted model solution while the prose tutorial is basically a placeholder; CF Step's hints and model code point to the same intended approach: bipartite-color each component and add the larger color class if the component is bipartite. Sources used: problem statement, official editorial page, CF Step hints, CF Step code.
The key phrase is all paths, not necessarily simple. Since vertices can repeat, this really means every possible walk starting from a vertex has to obey the alternating direction pattern. That is a very strong condition.
Fix a vertex and suppose it is beautiful.
First, consider any neighbor of . The path has length , and the first edge of an alternating path must be directed from the first vertex to the second. Therefore every edge incident to must be directed out of .
Now take a path . The second edge must be traversed against its direction, so the edge must be directed from to . Since could be any neighbor of , every edge incident to must be directed into .
Continue this along any shortest path from . If a vertex is at distance from , then:
So vertices get forced into two roles: "all outgoing" and "all incoming". No negotiation, no clever hack, no graph-matching magic despite the tag trying to look fancy.
Now look at an edge . If and have the same distance parity from , then they demand the same role. If both are "all outgoing", the edge would need to point away from both endpoints. If both are "all incoming", it would need to point into both endpoints. Both are impossible.
Therefore, if is beautiful, every edge in its connected component must connect opposite distance parities. That means the connected component is bipartite.
This proves an important upper bound:
If a non-bipartite component had even one beautiful vertex, the argument above would force the whole component to be bipartite, contradiction.
Now suppose a connected component is bipartite, with color classes and . If we orient every edge from to , then every vertex in is beautiful:
Because every walk in a bipartite graph alternates between and , this direction pattern works for every possible walk starting from any vertex in .
If we reverse all directions, then all vertices in become beautiful instead. So for this component, the best possible number of beautiful vertices is:
Connected components are independent because there are no edges between them. So the final answer is:
An isolated vertex is just a bipartite component with sizes and , so it contributes . That also matches the intuition: with no edges, there is nothing to violate.
Implementation:
Complexity:
per test case, with memory. Across all test cases this is safe because the total and total are each at most .
#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, m;
cin >> n >> m;
vector<vector<int>> g(n);
for (int i = 0; i < m; i++) {
int v, u;
cin >> v >> u;
--v;
--u;
g[v].push_back(u);
g[u].push_back(v);
}
vector<int> color(n, -1);
int ans = 0;
for (int s = 0; s < n; s++) {
if (color[s] != -1) continue;
queue<int> q;
q.push(s);
color[s] = 0;
int cnt[2] = {1, 0};
bool ok = true;
while (!q.empty()) {
int v = q.front();
q.pop();
for (int u : g[v]) {
if (color[u] == -1) {
color[u] = color[v] ^ 1;
cnt[color[u]]++;
q.push(u);
} else if (color[u] == color[v]) {
ok = false;
}
}
}
if (ok) ans += max(cnt[0], cnt[1]);
}
cout << ans << '\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, m;
cin >> n >> m;
vector<vector<int>> g(n);
for (int i = 0; i < m; i++) {
int v, u;
cin >> v >> u;
--v;
--u;
g[v].push_back(u);
g[u].push_back(v);
}
vector<int> color(n, -1);
int ans = 0;
for (int s = 0; s < n; s++) {
if (color[s] != -1) continue;
queue<int> q;
q.push(s);
color[s] = 0;
int cnt[2] = {1, 0};
bool ok = true;
while (!q.empty()) {
int v = q.front();
q.pop();
for (int u : g[v]) {
if (color[u] == -1) {
color[u] = color[v] ^ 1;
cnt[color[u]]++;
q.push(u);
} else if (color[u] == color[v]) {
ok = false;
}
}
}
if (ok) ans += max(cnt[0], cnt[1]);
}
cout << ans << '\n';
}
return 0;
}