Problem: 2063C - Remove Exactly Two
Language: java

Solution 1 (runtime: 905 ms):
import java.io.*;
import java.util.*;

public class RemoveExactlyTwo {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter pw = new PrintWriter(System.out);

        int tc = Integer.parseInt(br.readLine());

        while (tc-- > 0) {
            int N = Integer.parseInt(br.readLine());

            // if (N <)

            ArrayList<Integer>[] adj = new ArrayList[N];
            HashMap<Integer, Integer> degCnt = new HashMap<>();

            for (int i = 0; i < N; i++) {
                adj[i] = new ArrayList<>(); 
            }

            for (int i = 0; i < N-1; i++) {
                String s = br.readLine();
                StringTokenizer st1 = new StringTokenizer(s);

                int a = Integer.parseInt(st1.nextToken()) - 1;
                int b = Integer.parseInt(st1.nextToken()) - 1;

                adj[a].add(b);
                adj[b].add(a);
            }

            for (int i = 0; i < N; i++) {
                int deg = adj[i].size();
                degCnt.put(i, deg);
            }
            int res = 1;
            ArrayList<Integer> maxKeys = getBiggestKeys(degCnt);

            if (maxKeys.size() == 1) {
                res += degCnt.get(maxKeys.get(0)) - 1;
                degCnt.remove(maxKeys.get(0));

                for (int n : adj[maxKeys.get(0)]) {
                    degCnt.put(n, degCnt.get(n)-1);
                }

                res += degCnt.get(getBiggestKeys(degCnt).get(0)) - 1;
            } else {
                int max = degCnt.get(maxKeys.get(0));
                boolean done = false;
                for (int key : maxKeys) {
                    ArrayList<Integer> affected = adj[key];
                    int affectedCount = 0;
                    for (int v : affected) {
                        if (degCnt.get(v) == max) {
                            affectedCount++;
                        }
                    }

                    if (maxKeys.size() - affectedCount > 1) {
                        res = max * 2 - 1;
                        done = true;
                        break;
                    }
                }

                if (!done) {
                    res = max*2-2;
                }
            }

            pw.println(res);
        }

        pw.close();
    }

    static ArrayList<Integer> getBiggestKeys(HashMap<Integer, Integer> hm) {
        ArrayList<Integer> maxKeys = new ArrayList<>();
        for (Map.Entry<Integer, Integer> entry : hm.entrySet()) {
            int key = entry.getKey();
            int val = entry.getValue();

            if (maxKeys.size() == 0 || val >= hm.get(maxKeys.get(0))) {
                if (maxKeys.size() == 0 || val > hm.get(maxKeys.get(0))) {
                    maxKeys.clear();
                    maxKeys.add(key);
                } else {
                    maxKeys.add(key);
                }
            }
        }
        return maxKeys;
    }
}

Solution 2 (runtime: 1421 ms):
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class RemoveExactlyTwo {

    public static int[][] dfs(int src, int par, List<List<Integer>> arr) {

        int[][] new_components = new int[3][2];

        int first_max = 0, second_max = 0;

        for (int v : arr.get(src)) {
            if (par == v) continue;

            int[][] components = dfs(v, src, arr);

            new_components[0][0] = Math.max(new_components[0][0], components[0][0]);
            new_components[0][1] = Math.max(new_components[0][1], components[0][1]);

            new_components[1][0] = Math.max(new_components[1][0], Math.max(components[1][0], components[1][1]));
            new_components[1][1] = Math.max(new_components[1][1], components[0][0] + arr.get(src).size());
            new_components[1][1] = Math.max(new_components[1][1], components[0][1] + arr.get(src).size() - 1);
            
            new_components[2][0] = Math.max(new_components[2][0], Math.max(components[2][0], components[2][1]));
            new_components[2][1] = Math.max(new_components[2][1], components[1][0] + arr.get(src).size());
            new_components[2][1] = Math.max(new_components[2][1], components[1][1] + arr.get(src).size() - 1);

            if (first_max < components[1][0] || first_max < components[1][1]) {
                second_max = first_max;
                first_max = Math.max(components[1][0], components[1][1]);
            } else if (second_max < components[1][0] || second_max < components[1][1]) {
                second_max = Math.max(components[1][0], components[1][1]);
            }
        }

        if (arr.get(src).isEmpty()) {

            new_components[0][0] = 1;
            new_components[0][1] = Integer.MIN_VALUE/2;

            new_components[1][0] = Integer.MIN_VALUE/2;
            new_components[1][1] = 0;

            new_components[2][0] = Integer.MIN_VALUE/2;
            new_components[2][1] = Integer.MIN_VALUE/2;
            
        } else {
            new_components[2][0] = Math.max(first_max + second_max, new_components[2][0]);
        }

        return new_components;
    }
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int t =  Integer.parseInt(br.readLine());

        while(t-- > 0) {

           int n = Integer.parseInt(br.readLine());
           
           int edges = n - 1;

           List<List<Integer>> arr = new ArrayList<>();

           for (int i = 0; i < n; i++) arr.add(new ArrayList<>());

           while (edges-- > 0) {
                int[] e = Arrays.stream(br.readLine().split(" ")).mapToInt(Integer::parseInt).toArray();

                arr.get(e[0] - 1).add(e[1] - 1);
                arr.get(e[1] - 1).add(e[0] - 1);
           }

           int[][] components = dfs(0, -1, arr);

           System.out.println(Math.max(components[2][0], components[2][1]) - 1);

        }
    }
}