Problem: 2063C - Remove Exactly Two
Language: java

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

public class RemoveExactlyTwo
{
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);

        int t = in.nextInt();

        while (t-- > 0) {
            int n = in.nextInt();


            ArrayList<Integer>[] arr = new ArrayList[n];

            HashSet<Integer>[] s = new HashSet[n];

            for (int i = 0; i < n-1; i++) {
                int x = in.nextInt()-1;
                int y = in.nextInt()-1;

                if(arr[x] == null) {arr[x] = new ArrayList<>(); s[x] = new HashSet<>();}
                if(arr[y] == null) {arr[y] = new ArrayList<>(); s[y] = new HashSet<>();}

                arr[x].add(y); arr[y].add(x);
                s[x].add(y); s[y].add(x);
            }

            Comparator<int[]> comparator = (a, b) -> Integer.compare(b[0], a[0]);

            PriorityQueue<int[]> pq = new PriorityQueue<>(comparator);

//            pq.add(new int[]{n,0});

            HashSet<Integer> vis = new HashSet<>();

            int ans = dfs(pq, 0, vis, s, arr);

            System.out.println(ans);

        }



    }

    public static int dfs(PriorityQueue<int[]> pq, int m, HashSet<Integer> vis, HashSet<Integer>[] s, ArrayList<Integer>[] arr)
    {
        vis.add(m);
        int v = s[m].size();

        int max = 0;

        if(pq.isEmpty()){
            max = 0;
        }
        else if(s[m].contains(pq.peek()[1])) {
            int[] a = pq.poll();
            max = v + a[0] - 2;
            if(!pq.isEmpty()) max = Math.max( v + a[0] - 2, v + pq.peek()[0] - 1);
            pq.add(a);
        }
        else if(!s[m].contains(pq.peek()[1]))
        {
            max = Math.max(max, v + pq.peek()[0] - 1);
        }

        pq.add(new int[]{v, m});

        for (int i = 0; i < arr[m].size(); i++) {
            if(vis.contains(arr[m].get(i))) continue;
            max = Math.max(max, dfs(pq,arr[m].get(i), vis, s, arr));
        }

        return max;

    }



    /*          ─────────▄▄───────────────────▄▄──
                ──────────▀█───────────────────▀█─
                ──────────▄█───────────────────▄█─
                ──█████████▀───────────█████████▀─
                ───▄██████▄─────────────▄██████▄──
                ─▄██▀────▀██▄─────────▄██▀────▀██▄
                ─██────────██─────────██────────██
                ─██───██───██─────────██───██───██
                ─██────────██─────────██────────██
                ──██▄────▄██───────────██▄────▄██─
                ───▀██████▀─────────────▀██████▀──
                ──────────────────────────────────
                   ────────────────────────────
                    ─────────────────────────
                     ──────█████████████───
                     ──────────────────────
                     ──────────────────────
     */
}


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);

        }
    }
}