#include <bits/stdc++.h>
using namespace std;
 
// We'll use 0-indexing for nodes.
 
// Global variables
int N;
vector<vector<int>> fmat; // fmat[i][j] = number of distinct colors on path i<->j
// ********** Union–Find for 1‐comps **********
vector<int> uf_parent;
 
int uf_find(int a) {
    if(uf_parent[a] == a) return a;
    return uf_parent[a] = uf_find(uf_parent[a]);
}
 
void uf_union(int a, int b) {
    a = uf_find(a); b = uf_find(b);
    if(a == b) return;
    uf_parent[b] = a;
}
 
// ********** Global data for tree reconstruction **********
// We will store the final tree (which will have exactly N-1 edges)
vector<pair<int,int>> treeEdges; // each edge is (u,v), 0-indexed
// The final tree will be stored as an adjacency list:
vector<vector<int>> treeAdj;
 
// ********** LCA preprocessing **********
vector<int> par, depth;
 
void dfsTree(int u, int p) {
    par[u] = p;
    for (int v : treeAdj[u]) {
        if (v == p) continue;
        depth[v] = depth[u] + 1;
        dfsTree(v, u);
    }
}
 
// Simple LCA (O(n) per query, which is acceptable for N<=3000)
int getLCA(int u, int v) {
    while(depth[u] > depth[v]) u = par[u];
    while(depth[v] > depth[u]) v = par[v];
    while(u != v) {
        u = par[u];
        v = par[v];
    }
    return u;
}
 
// Returns the number of distinct colors on the unique path between u and v in the final tree.
// Uses the global "colors" vector.
int getDistinctOnPath(int u, int v, const vector<int>& colors) {
    int l = getLCA(u,v);
    vector<bool> seen(N+1, false);
    int cnt = 0;
    // Walk from u up to (but not including) l
    int cur = u;
    while(cur != l) {
        if (!seen[colors[cur]]) { seen[colors[cur]] = true; cnt++; }
        cur = par[cur];
    }
    // Walk from v up to (but not including) l
    cur = v;
    while(cur != l) {
        if (!seen[colors[cur]]) { seen[colors[cur]] = true; cnt++; }
        cur = par[cur];
    }
    // Count the LCA once
    if (!seen[colors[l]]) { cnt++; }
    return cnt;
}
 
// ********** DFS to assign colors **********
// colors[u] will hold the color assigned to node u (from 1 to N)
vector<int> colors;
// "coloredList" will store all nodes that have already been assigned a color.
vector<int> coloredList;
 
// Recursive DFS that “colors” the tree so that for every already–colored node w, 
// the distinct colors on the path from w to u equals fmat[w][u].
void dfsColor(int u, int p) {
    // For each child v, decide its color
    for (int v : treeAdj[u]) {
        if (v == p) continue;
 
        // Try candidate colors from 1 to N.
        for (int cand = 1; cand <= N; cand++) {
            // We must have: if edge (u,v) is between different 1–comps, then f(u,v)==2,
            // so in our tree adjacent nodes must have different colors.
            if (cand == colors[u]) continue;
 
            colors[v] = cand;
 
            bool ok = true;
            // Check the condition for every already colored node (other than v itself)
            for (int w : coloredList) {
                int cnt = getDistinctOnPath(w, v, colors);
                if (cnt != fmat[w][v]) {
                    ok = false;
                    break;
                }
            }
            if (ok) break;
        }
        coloredList.push_back(v);
        dfsColor(v, u);
    }
}
 
// ********** Main function **********
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
 
    int subtask;
    cin >> subtask >> N;
    fmat.assign(N, vector<int>(N, 0));
    for (int i = 0; i < N; i++){
        for (int j = 0; j < N; j++){
            cin >> fmat[i][j];
        }
    }
 
    // === Phase 1: Contract nodes that must be the same color (1‐comps) ===
    uf_parent.resize(N);
    for (int i = 0; i < N; i++) uf_parent[i] = i;
    for (int i = 0; i < N; i++){
        for (int j = i+1; j < N; j++){
            if (fmat[i][j] == 1) {
                uf_union(i,j);
            }
        }
    }
 
    // Identify for every node its representative (the unique 1–comp id)
    vector<int> repId(N, -1);
    for (int i = 0; i < N; i++){
        repId[i] = uf_find(i);
    }
 
    // For every non–representative, attach it immediately to its representative.
    // (We choose the representative to be the one with the smallest index in that comp.)
    vector<bool> isRep(N, false);
    for (int i = 0; i < N; i++){
        if (repId[i] == i) { isRep[i] = true; }
    }
    for (int i = 0; i < N; i++){
        if (!isRep[i]){
            // attach i to its rep
            treeEdges.push_back({ repId[i], i });
        }
    }
 
    // === Phase 2: Among the representatives, use edges with f==2 to “reconstruct” the contracted tree ===
    // Collect all representatives.
    vector<int> reps;
    for (int i = 0; i < N; i++){
        if (isRep[i]) reps.push_back(i);
    }
    // Build a graph among representatives using candidate edges (f==2)
    vector<vector<int>> repGraph(N);
    int R = reps.size();
    for (int i = 0; i < R; i++){
        for (int j = i+1; j < R; j++){
            int u = reps[i], v = reps[j];
            if (fmat[u][v] == 2) {
                repGraph[u].push_back(v);
                repGraph[v].push_back(u);
            }
        }
    }
    // Find a spanning tree on the representatives (which is guaranteed to exist)
    vector<bool> vis(N, false);
    queue<int>q;
    if (!reps.empty()){
        q.push(reps[0]);
        vis[reps[0]] = true;
    }
    while(!q.empty()){
        int u = q.front(); q.pop();
        for (int v : repGraph[u]){
            if (!vis[v]){
                vis[v] = true;
                q.push(v);
                treeEdges.push_back({ u, v });
            }
        }
    }
 
    // === Build the final tree’s adjacency list ===
    treeAdj.assign(N, vector<int>());
    for (auto &e : treeEdges) {
        int u = e.first, v = e.second;
        treeAdj[u].push_back(v);
        treeAdj[v].push_back(u);
    }
 
    // === Phase 3: Assign colors by a DFS (the “greedy‐check” procedure) ===
    colors.assign(N, 0);
    // We choose an arbitrary root – say, the smallest representative (or 0)
    int root = 0;
    colors[root] = 1;
    coloredList.push_back(root);
 
    // Precompute parent and depth for LCA queries.
    par.assign(N, -1);
    depth.assign(N, 0);
    dfsTree(root, -1);
 
    dfsColor(root, -1);
 
    // === Output the answer ===
    // First line: colors (convert back to 1-indexed if desired)
    for (int i = 0; i < N; i++){
        cout << colors[i] << (i+1==N? "\n" : " ");
    }
    // Next N-1 lines: tree edges (we output 1-indexed nodes)
    for (auto &e : treeEdges){
        cout << e.first+1 << " " << e.second+1 << "\n";
    }
 
    return 0;
}
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... | 
| # | Verdict | Execution time | Memory | Grader output | 
|---|
| Fetching results... |