Problem: 2063C - Remove Exactly Two
Language: C++23 (GCC 14-64, msys2)

Previous submission (verdict: Wrong answer on test 12):
#include <bits/stdc++.h>
using namespace std;
 
typedef long long ll;
 
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
 
    int t; 
    cin >> t;
    while(t--){
        int n; 
        cin >> n;
        vector<vector<int>> adj(n+1);
        vector<int> deg(n+1,0);
        vector<pair<int,int>> edges;
 
        // Lectura de las n-1 aristas.
        for (int i = 1; i <= n-1; i++){
            int u, v;
            cin >> u >> v;
            adj[u].push_back(v);
            adj[v].push_back(u);
            deg[u]++;
            deg[v]++;
            edges.push_back({u,v});
        }
 
        // Ordenamos las listas de adyacencia para cada vértice (para usar binary_search).
        for (int i = 1; i <= n; i++){
            sort(adj[i].begin(), adj[i].end());
        }
 
        // Caso 1: parejas adyacentes.
        int bestAdj = -1;
        for(auto &e : edges){
            int u = e.first, v = e.second;
            int cand = deg[u] + deg[v] - 2;
            bestAdj = max(bestAdj, cand);
        }
 
        // Caso 2: parejas NO adyacentes.
        int bestNonAdjSum = -1;
        vector<pair<int,int>> degList;
        degList.reserve(n);
        for (int i = 1; i <= n; i++){
            degList.push_back({deg[i], i});
        }
        // Ordenamos de mayor a menor grado.
        sort(degList.begin(), degList.end(), [](auto &a, auto &b){
            return a.first > b.first;
        });
 
        // Usamos los primeros X vértices; aumentamos X a min(n,2000) para mayor cobertura.
        int X = min(n, 2000);
        for (int i = 0; i < X; i++){
            for (int j = i+1; j < X; j++){
                int u = degList[i].second;
                int v = degList[j].second;
                // Si u y v son adyacentes, se salta.
                if(binary_search(adj[u].begin(), adj[u].end(), v))
                    continue;
                int sum = deg[u] + deg[v];
                bestNonAdjSum = max(bestNonAdjSum, sum);
            }
        }
 
        int candNonAdj = (bestNonAdjSum == -1 ? -1 : bestNonAdjSum - 1);
 
        int ans = max(bestAdj, candNonAdj);
        cout << ans << "\n";
    }
    return 0;
}

Submission (verdict: Accepted):
#include <bits/stdc++.h>
using namespace std;
 
typedef long long ll;
 
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
 
    int t;
    cin >> t;
    while(t--){
        int n;
        cin >> n;
        // Notar: el árbol tiene n vertices y n-1 aristas.
        vector<vector<int>> adj(n+1);
        vector<int> deg(n+1, 0);
        vector<pair<int,int>> edges;
        edges.reserve(n-1);
 
        for (int i = 1; i < n; i++){
            int u, v;
            cin >> u >> v;
            // Agregamos la arista en ambos sentidos.
            adj[u].push_back(v);
            adj[v].push_back(u);
            deg[u]++;
            deg[v]++;
            edges.push_back({u,v});
        }
 
        // Ordenamos la lista de vecinos de cada vértice para poder usar binary_search.
        for (int i = 1; i <= n; i++){
            sort(adj[i].begin(), adj[i].end());
        }
 
        // ------------------------------
        // Caso 1: pares adyacentes.
        // Para cada arista (u,v), la respuesta es: deg(u)+deg(v)-2.
        int bestAdj = -1;
        for(auto &e : edges){
            int u = e.first, v = e.second;
            bestAdj = max(bestAdj, deg[u] + deg[v] - 2);
        }
 
        // ------------------------------
        // Caso 2: pares NO adyacentes.
        // Queremos maximizar: deg(u) + deg(v) - 1.
        // Primero, construimos una lista de vértices ordenados por grado (descendente).
        vector<pair<int,int>> sortedVerts; // (grado, vértice)
        sortedVerts.reserve(n);
        for (int i = 1; i <= n; i++){
            sortedVerts.push_back({deg[i], i});
        }
        sort(sortedVerts.begin(), sortedVerts.end(), [](const pair<int,int> &a, const pair<int,int> &b){
            return a.first > b.first;
        });
 
        int bestNonAdj = 0; // Valor para pares no adyacentes (mínimo posible es 1+1-1 = 1).
 
        // Para cada vértice u (tomado de la lista ordenada) buscamos el primer candidato v en la lista
        // tal que v no sea u y no esté en la lista de vecinos de u.
        // Además, usamos un corte (threshold) para no recorrer candidatos con grado demasiado bajo.
        for (auto &p : sortedVerts){
            int uDeg = p.first;
            int u = p.second;
            // Calcular el máximo grado posible para una pareja con u:
            int bestPossiblePartner = 0;
            if(sortedVerts[0].second == u){
                if(sortedVerts.size() >= 2)
                    bestPossiblePartner = sortedVerts[1].first;
            } else {
                bestPossiblePartner = sortedVerts[0].first;
            }
            int potential = uDeg + bestPossiblePartner - 1;
            if(potential <= bestNonAdj) continue; // No puede mejorar.
 
            // Para mejorar, se requiere que para la pareja (u,v) se tenga:
            //   uDeg + vDeg - 1 > bestNonAdj   =>   vDeg > bestNonAdj - uDeg + 1.
            int needed = bestNonAdj - uDeg + 1;
 
            // Recorremos la lista global para encontrar a v (ordenada de mayor a menor).
            for (auto &q : sortedVerts){
                int vDeg = q.first;
                int v = q.second;
                if(vDeg < needed) break; // Los siguientes tienen aún menor grado.
                if(v == u) continue;
                // Verificamos si u y v son adyacentes.
                if(binary_search(adj[u].begin(), adj[u].end(), v))
                    continue;
                // Encontramos un candidato válido.
                int candidateVal = uDeg + vDeg - 1;
                bestNonAdj = max(bestNonAdj, candidateVal);
                // Para u, el primer candidato (con mayor grado) es el óptimo, rompemos.
                break;
            }
        }
 
        int ans = max(bestAdj, bestNonAdj);
        cout << ans << "\n";
    }
    return 0;
}