Problem: 2063C - Remove Exactly Two
Language: c++17 

Solution 1 (runtime: 1281 ms):
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define ll long long
#define vi vector<int>
#define vvi vector<vector<int>>
#define pi pair<int,int>
#define pb push_back
#define forn(i, n) for (int i = 0; i < int(n); ++i)
const int MOD =   998244353;
const int INF = 1e18;
// const int INF=1e15;
 
void read( vi &nums){for(int i=0;i<nums.size();i++) cin>>nums[i];}
vector<int> divisors(int n) { vector<int> div; for (int i = 1; i * i <= n; i++) { if (n % i == 0) { div.push_back(i); if (i != n / i) div.push_back(n / i); } } sort(div.begin(), div.end()); return div; }
vector<int> primefact(int n) { vector<int> ans; for(int i = 2; i * i <= n; i++) { while(n % i == 0) { ans.push_back(i); n = n / i; } } if(n > 1) ans.push_back(n); sort(ans.begin(), ans.end()); return ans; }
int mex(vector<int> arr) { int N = arr.size(); sort(arr.begin(), arr.end()); int mex = 0; for (int idx = 0; idx < N; idx++) { if (arr[idx] == mex) mex += 1; } return mex; }
int lcm1(int a, int b) { return (a * b) / __gcd(a, b); }
int msb(int n) { for (int i = 60; i >= 0; i--) { if (n & (1ll << i)) return i; } return -1; }
void ivec(vector<int> &nums){ for(int i=0;i<nums.size();i++) cin>>nums[i]; }
bool isPowerOfTwo(int n) { return n > 0 && (ceil(log2(n)) == floor(log2(n))); }
int cal(int b, int a) { return (b + a - 1) / a; }
int modAdd3(int a, int b,int c, int m) { return ((a % m) + (b % m)+(c%m)) % m; }
int modAdd(int a, int b, int m) { return ((a % m) + (b % m)) % m; }
int modSub(int a, int b, int m) { return ((a % m) - (b % m) + m) % m; }
int modMul(int a, int b, int m) { return ((a % m) * (b % m)) % m; }
// unsigned int countSetBits(unsigned int n) { return __builtin_popcount(n); }
int power(int x, unsigned int y) { if (y == 0) return 1; else if (y % 2 == 0) return power(x, y / 2) * power(x, y / 2); else return x * power(x, y / 2) * power(x, y / 2); }
int countDigit(int n) { if (n == 0) return 1; int count = 0; while (n != 0) { n = n / 10; ++count; } return count; }
void ncrin1(int N, vector<vector<int>> &C) { for (int i = 0; i < N; ++i) for (int j = 0; j <= i; ++j) C[i][j] = (j == 0 || j == i) ? 1 : (C[i - 1][j] + C[i - 1][j - 1]) % MOD; }
ll ncr(ll N, ll R) { if(N<R) return 0; ll res=1; for(int i=0; i<R; i++) { res = res*(N-i); res = res / (i+1); } return res; }
int total(int i, int j, vector<int>& prefixsum) { return (i > 0) ? prefixsum[j] - prefixsum[i - 1] : prefixsum[j]; }
bool isVowel(char ch) { return (ch = tolower(ch)) == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u'; }
 int countSetBits(int n) {
    return __builtin_popcount(n);
}
void  print(vi &nums){ for(int i=0;i<nums.size();i++) cout<<nums[i]<<" ";cout<<endl;}

vector<bool> SieveOfEratosthenes(int n) {
    vector<bool>  prime(n+1,true);
    prime[0]=false;prime[1]=0;
    for (int p = 2; p * p <= n; p++) {
        if (prime[p]) {
            for (int i = p * p; i <= n; i += p)
                prime[i] = false;
        }
    }
    return prime;
}
 
 
class DisjointSet {
public: 
    vector<int> rank, parent, size; 
    DisjointSet(int n) : rank(n+1, 0), parent(n+1), size(n+1, 1) { for(int i = 0; i <= n; i++) parent[i] = i; }
    int findUPar(int node) { return (node == parent[node]) ? node : (parent[node] = findUPar(parent[node])); }
    void unionByRank(int u, int v) { int ulp_u = findUPar(u), ulp_v = findUPar(v); if (ulp_u == ulp_v) return; if (rank[ulp_u] < rank[ulp_v]) parent[ulp_u] = ulp_v; else if (rank[ulp_v] < rank[ulp_u]) parent[ulp_v] = ulp_u; else { parent[ulp_v] = ulp_u; rank[ulp_u]++; } }
    void unionBySize(int u, int v) { int ulp_u = findUPar(u), ulp_v = findUPar(v); if (ulp_u == ulp_v) return; if (size[ulp_u] < size[ulp_v]) { parent[ulp_u] = ulp_v; size[ulp_v] += size[ulp_u]; } else { parent[ulp_v] = ulp_u; size[ulp_u] += size[ulp_v]; } }
}; 
 int calc(string &a,string &b){
    int ans=0;
  for(int i=0;i<a.size();i++) ans+=abs((int)(a[i]-b[i]));
  return ans;
}
 
// class UnionFind {
// public:
//     vector<int> rank, p, nearestRight;
//     UnionFind(int n) { rank.assign(n, 0); p.assign(n, 0); nearestRight.assign(n, 0); iota(p.begin(), p.end(), 0); iota(nearestRight.begin(), nearestRight.end(), 0); }
//     int findSet(int i) { return (p[i] == i) ? i : (p[i] = findSet(p[i])); }
//     void unionSet(int i, int j) { 
//         int x = findSet(i), y = findSet(j);
//         if (x != y) { if (rank[x] < rank[y]) swap(x, y); nearestRight[x] = max(nearestRight[x], nearestRight[y]); if (rank[x] == rank[y]) rank[x]++; p[y] = x; }
//     }
//     int findRight(int i) { return nearestRight[findSet(i)]; }
// };

int modExp(int base, int exp, int mod){int res=1;while(exp>0){if(exp%2==1)res=modMul(res,base,mod);base=modMul(base,base,mod);exp/=2;}return res;}
vector<int> fact,invFact;void precomputeFactorial(int n,int mod){fact.resize(n+1,1),invFact.resize(n+1,1);for(int i=2;i<=n;i++)fact[i]=modMul(fact[i-1],i,mod);invFact[n]=modExp(fact[n],mod-2,mod);for(int i=n-1;i>=2;i--)invFact[i]=modMul(invFact[i+1],i+1,mod);}
int nCr(int n,int r,int mod){return r>n?0:modMul(fact[n],modMul(invFact[r],invFact[n-r],mod),mod);}






// Main function

bool so(int mid, int n, int s, int d) {
    return (n * 100) <= (s + mid) * d;
}
struct Pair {
    int val, vertex;
};
struct cmp {
    bool operator()(const Pair &a, const Pair &b) const {
        if(a.val == b.val) return a.vertex < b.vertex;
        return a.val < b.val;
    }
};

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int tc;
    cin >> tc;
    while (tc--) {
        int n;
        cin >> n;
        
        // Read the tree and compute original degrees.
        vi d(n + 1, 0); // d[i] will store the original degree of vertex i.
        vector<vi> adj(n + 1);
        for (int i = 0; i < n - 1; i++) {
            int u, v;
            cin >> u >> v;
            adj[u].pb(v);
            adj[v].pb(u);
            d[u]++;
            d[v]++;
        }
        
        if (n <= 2) {
            cout << 0 << "\n";
            continue;
        }
        
        // eff will hold the current (effective) degrees.
        vi eff = d;
        
        // Build a multiset of (effective degree, vertex) for all vertices.
        multiset<Pair, cmp> ms;
        for (int i = 1; i <= n; i++) {
            ms.insert({eff[i], i});
        }
        
        int ans = 0;
        
        // Try every vertex i as the first removal.
        for (int i = 1; i <= n; i++) {
            // Remove vertex i from the multiset.
            ms.erase({eff[i], i});
            
            // For every neighbor of i, simulate the effect of i's removal:
            // their effective degree decreases by 1.
            // We'll remove and reinsert each neighbor to update its value.
            vector<int> affected;  // store affected neighbor ids to revert later.
            for (int nb : adj[i]) {
                // Check if nb is still in ms (it might be already removed in this simulation)
                auto it = ms.find({eff[nb], nb});
                if (it != ms.end()) {
                    affected.push_back(nb);
                    ms.erase(it);
                    eff[nb]--;   // decrease effective degree because the edge to i is gone
                    ms.insert({eff[nb], nb});
                }
            }
            
            // Now, the maximum effective degree among the remaining vertices:
            int currentMax = 0;
            if (!ms.empty()) {
                // Since ms is sorted in ascending order, the last element is the maximum.
                auto it = ms.end();
                it--;
                currentMax = it->val;
            }
            // When removing vertex i first and then the best candidate j,
            // the total number of connected components will be:
            // 1 (original component) + (d[i]-1) + (effective degree of j - 1)
            // = d[i] + (effective degree of j) - 1.
            ans = max(ans, d[i] + currentMax - 1);
            
            // Revert the changes for all affected neighbors.
            for (int nb : affected) {
                auto it = ms.find({eff[nb], nb});
                if (it != ms.end()) {
                    ms.erase(it);
                    eff[nb]++; // revert back to original effective degree for nb
                    ms.insert({eff[nb], nb});
                }
            }
            // Reinsert vertex i back into the multiset.
            ms.insert({eff[i], i});
        }
        
        cout << ans << "\n";
    }
    
    return 0;
}

Solution 2 (runtime: 531 ms):
#include <bits/stdc++.h>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;   
using namespace std;
typedef long long ll;

//
typedef tree<ll, null_type, less<ll>, rb_tree_tag, tree_order_statistics_node_update> ordered_set;
typedef tree<ll, null_type, less_equal<ll>, rb_tree_tag, tree_order_statistics_node_update> ordered_multiset;
typedef tree<pair<ll,ll>, null_type, less<pair<ll,ll>>, rb_tree_tag, tree_order_statistics_node_update> ordered_pset;
//
#define ld long double
#define pb push_back
/* You may enter other macros defined by you */
#define vi vector<ll>
#define rep(i,a,b) for(ll i=a;i<b;i++)
#define rep1(i,a,b) for(ll i=a;i<=b;i++)
#define ff first
#define ss second
#define pll pair<ll, ll>
#define vpll vector<pair<ll,ll> >
#define vvl vector<vector<ll> >
#define printv(a) for(auto x: a){cout<<x<<" ";}cout<<"\n";
#define input(a,n) rep(i,0,n)cin>>a[i];
#define input1(a,n) rep1(i,1,n)cin>>a[i];
#define mp make_pair

#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()
#define minv(a) *min_element(all(a))
#define maxv(a) *max_element(all(a))
void yes() { cout<<"YES\n"; }
void no() { cout<<"NO\n"; }
// random number generator
mt19937 rnd(593); 

  
const ll mod = 1e9+7;
//const ll mod = 998244353;
const ld PI = acos(-1);
const ld EPS = 1e-9;
const ll INF = 1e18;
const ll N=3e5+10;
inline int add(int x, int y) { int ret = x + y; if (ret >= mod) ret -= mod; return ret; }
inline int sub(int x, int y) { int ret = (x - y); if (ret < 0) ret += mod; return ret; }
inline int mul(int x, int y) { int ret = (1ll * x * y) % mod; return ret; }
int exp(int a, int b) { int ret = 1; while (b) { if (b & 1) ret = mul(ret, a); a = mul(a, a); b >>= 1;} return ret; }
int dv(int a, int b) { int ret = exp(b, mod - 2); ret = mul(ret, a); return ret; }

vvl adj;

multiset<ll> s;

ll ans=-1;

void dfs(ll u,ll e){
  s.erase(s.find(adj[u].size()));
  if(u!=e){
    s.erase(s.find(adj[e].size()));
  }
  for(auto x: adj[u]){
    if(x==e)continue;
    ans=max(ans,adj[u].size()+adj[x].size()-2ll);
    s.erase(s.find(adj[x].size()));
  }
  if(s.size()!=0){
    ans=max(ans,adj[u].size()+*s.rbegin()-1ll);
  }

  s.insert(adj[u].size());
  if(u!=e)
  s.insert(adj[e].size());
  for(auto x: adj[u]){
    if(x==e)continue;
    s.insert(adj[x].size());
  }
  for(auto x: adj[u]){
    if(x==e)continue;
    dfs(x,u);
  }
}


void solve(ll t){   
  ll n;cin>>n;
  ans=-1;
  s.clear();
  adj.assign(n+1,vi(0));
  rep(i,0,n-1){
    ll u,v;cin>>u>>v;
    adj[u].pb(v);
    adj[v].pb(u);
  }
  rep1(i,1,n){
    s.insert(adj[i].size());
  }
  dfs(1,1);
  cout<<ans<<endl;

}
    
int main(){

  ios::sync_with_stdio(0);
  cin.tie(0); cout.tie(0);
  int t;
  cin>>t;
  ll tt=t;
  while(t--)
    solve(tt-t);
  cerr << "Time : " << 1000 * ((double)clock()) / (double)CLOCKS_PER_SEC << "ms\n";

  return 0; 
}