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 an edge, the actual numbers in the permutation do not matter directly. Only whether one endpoint gets a larger value than the other matters.
Each edge has a preferred relative order: if , it wants ; otherwise it is fine to make when is better.
Think of every edge as a directed constraint: point from the vertex that should get the larger value to the vertex that should get the smaller value.
The scary-looking part is whether these constraints can conflict. But the graph is a tree, and any orientation of a tree is a DAG. No undirected cycle means no directed cycle. Nice, for once.
Topologically sort the directed tree. Give larger permutation values to earlier vertices in that order. Then every edge gets its maximum possible contribution, so the answer is optimal.
The whole trick is to stop thinking about the permutation values as exact numbers.
For an edge with :
So every edge only cares about the relative order of its two endpoints.
Best choice per edge
For each edge, we obviously want the bigger of and .
If , then this edge wants:
So vertex should appear earlier if we sort vertices from largest value to smallest value.
If , then this edge wants:
So vertex should appear earlier.
If , the edge does not care. Pick either direction; it changes nothing.
This gives us one ordering constraint per edge. For example, if an edge wants , draw a directed edge:
meaning: must receive a larger value than .
Why can we satisfy every edge?
Usually, constraints like this can conflict. For example, if we had:
then we would be cooked, because that asks for:
which is impossible.
But here the original graph is a tree.
A tree has no undirected cycles. A directed cycle would also require an undirected cycle underneath it. Since there is no undirected cycle, there cannot be a directed cycle either.
So after orienting every tree edge however we want, the result is always a DAG.
That means a topological ordering always exists.
Building the permutation
After directing edges, run a topological sort.
Suppose the topological order is:
For every directed edge , appears before in this order.
Now assign values like this:
So earlier vertices get larger values.
Then for every directed edge :
which is exactly what that edge wanted.
Therefore every edge contributes:
The total value becomes:
No permutation can do better than that, because each edge individually contributes at most . Since we reach that upper bound for every edge, the permutation is optimal. Boom. The tree did all the heavy lifting.
Algorithm
For each test case:
Complexity
Each edge is processed once, and topological sorting is linear.
Time complexity:
per test case.
Memory complexity:
#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> indeg(n + 1, 0);
for (int i = 0; i < n - 1; i++) {
int u, v;
ll x, y;
cin >> u >> v >> x >> y;
int a, b;
if (x >= y) {
a = u;
b = v;
} else {
a = v;
b = u;
}
g[a].push_back(b);
indeg[b]++;
}
queue<int> q;
for (int i = 1; i <= n; i++) {
if (indeg[i] == 0) q.push(i);
}
vector<int> order;
while (!q.empty()) {
int u = q.front();
q.pop();
order.push_back(u);
for (int v : g[u]) {
indeg[v]--;
if (indeg[v] == 0) q.push(v);
}
}
vector<int> p(n + 1);
for (int i = 0; i < n; i++) {
p[order[i]] = n - i;
}
for (int i = 1; i <= n; i++) {
cout << p[i] << ' ';
}
cout << '\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> indeg(n + 1, 0);
for (int i = 0; i < n - 1; i++) {
int u, v;
ll x, y;
cin >> u >> v >> x >> y;
int a, b;
if (x >= y) {
a = u;
b = v;
} else {
a = v;
b = u;
}
g[a].push_back(b);
indeg[b]++;
}
queue<int> q;
for (int i = 1; i <= n; i++) {
if (indeg[i] == 0) q.push(i);
}
vector<int> order;
while (!q.empty()) {
int u = q.front();
q.pop();
order.push_back(u);
for (int v : g[u]) {
indeg[v]--;
if (indeg[v] == 0) q.push(v);
}
}
vector<int> p(n + 1);
for (int i = 0; i < n; i++) {
p[order[i]] = n - i;
}
for (int i = 1; i <= n; i++) {
cout << p[i] << ' ';
}
cout << '\n';
}
return 0;
}