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

Solution 1 (runtime: 328 ms):
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define vi vector<int>
#define cy cout << "YES" << endl
#define cn cout << "NO" << endl
#define loop(i, x, y) for (int i = x; i < y; i++)
#define rloop(i, x, y) for (int i = x; i >= y; i--)
#define all(arr) arr.begin(), arr.end()
#define rt return
#define mpp map<int, int>
#define ff first
#define ss second
#define pb push_back
#define sortv(arr) sort(arr.begin(), arr.end())
#define rsortv(arr) sort(arr.begin(), arr.end(), greater<int>())
#define pii pair<int, int>
#define br cout << endl
#define dbg(a) cout << a << endl
#define ct continue
#define disp(a)                        \
  {                                    \
    for (int i = 0; i < a.size(); i++) \
      cout << a[i] << " ";             \
    cout << endl;                      \
  }
#define inp(a)                         \
  {                                    \
    for (int i = 0; i < a.size(); i++) \
      { cin >> a[i]; }                 \
  }
const int mod = 998244353;
long long mod_exp(long long base, long long exp, long long mod) {
    long long result = 1;
    while (exp > 0) {
        if (exp % 2 == 1) { // If exp is odd
            result = (result * base) % mod;
        }
        base = (base * base) % mod; // Square the base
        exp /= 2; // Halve the exponent
    }
    return result;
}
 
long long mod_inverse(long long a, long long mod) {
    return mod_exp(a, mod - 2, mod); // Using modular exponentiation
}
void dfs(int i,vi& vis,vi adj[]){
   vis[i]=1;
   for(auto it :adj[i]){
    if(!vis[it])dfs(it,vis,adj);
   }
}
void Dinesh() {
  int n;
  cin>>n;
  vi deg(n+1);
  set<pii>edges;
  loop(i,0,n-1){
    int u,v;
    cin>>u>>v;
    deg[u]++;
    deg[v]++;
    edges.insert({u,v});
  }
  int mx1=*max_element(deg.begin(),deg.end()),idx1=max_element(deg.begin(),deg.end())-deg.begin();
  int ans=0;
  // cout<<mx1<<" "<<idx1;br;
  int idx2=0;
  loop(i,1,n+1){
    if(deg[i]==mx1 && i!=idx1){idx2=i;break;}
  }
  loop(i,1,n+1){
    if(i!=idx1 && edges.find({idx1,i})==edges.end() && edges.find({i,idx1})==edges.end()){
      ans=max(ans,mx1+deg[i]-1);
    }
    else if(i!=idx1){
      ans=max(ans,mx1+deg[i]-2);
    }

  }
  if(idx2!=0)loop(i,1,n+1){
    if(i!=idx2 && edges.find({idx2,i})==edges.end() && edges.find({i,idx2})==edges.end()){
      ans=max(ans,mx1+deg[i]-1);
    }
    else if(i!=idx1){
      ans=max(ans,mx1+deg[i]-2);
    }

  }
  dbg(ans);
  
  
 
}

int32_t main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while (t--) {
        Dinesh();
    }
    return 0;
}


Solution 2 (runtime: 265 ms):
#include <bits/stdc++.h>
// #include<ext/pb_ds/assoc_container.hpp>
// #include<ext/pb_ds/tree_policy.hpp>
 
#pragma GCC target ("avx2")
#pragma GCC optimize ("O3")
#pragma GCC optimize("Ofast")
// #pragma GCC optimize ("unroll-loops")
// #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
// #pragma GCC target("avx,avx2,avx512,fma") 
 
// Macros
#define F first
#define S second
#define rep(i,n) for(int i=0; i<n; ++i)
#define sortv(v) sort(v.begin(), v.end())
#define rev(v) reverse(v.begin(), v.end())
#define pb push_back
#define mp make_pair
#define mod 1e9 + 7
#define MOD  998244353
#define mod2 1e8
#define sc(n) scanf("%d",&n)
#define sza(x) ((int)x.size())
#define scl(n) scanf("%lld",&n)
#define max(a,b) std::max(a,b)
#define min(a,b) std::min(a,b)
#define ipair pair<pair<int, int>,vector<int>>
 
using namespace std;
// using namespace __gnu_pbds;
// using namespace std::chrono;
 
typedef vector<int> veci;
typedef vector<long long int> vecll;
// typedef __gnu_pbds::tree<int, __gnu_pbds::null_type, less<int>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update> ordered_set;
 
 
// Aliases
using ll = long long;
using ull = unsigned long long;
using ld = long double;
 
// Constants
const ll INF = 2e18;
const double PI = 3.14159265358979;
 
// Functions
 
vector<int> sieve(ll n)
{
    vector<int> prime(n+1,1);
    for (int p = 2; p * p <= n; p++) {
        if (prime[p] == 1) {
            for (int i = p * p; i <= n; i += p)
                prime[i] = 0;
        }
    }
 
    vector<int> ans;
    for(int i = 2; i <= n; ++i)
    {
        if(prime[i] == 1)
        {
            ans.push_back(i);
        }
    }
    return ans;
}
 
ll gcd(ll a, ll b) { 
    if (b == 0) { return a;} return gcd(b, a % b);
}
 
ll lcm(ll a, ll b) {
    return (a*b)/gcd(a,b);
}
 
bool check_prime(ll n) {
    if (n <= 1)
        return false;
    if (n <= 3)
        return true;
    if (n % 2 == 0 || n % 3 == 0)
        return false;
    for (int i = 5; i * i <= n; i = i + 6)
        if (n % i == 0 || n % (i + 2) == 0)
            return false;
    return true;
}
 
int binary_search(ll a[], int n, ll target)
{
    int start = 0;
    int end = n-1;
    while(start <= end) {
        int mid = start + ((end-start)/2);
        if(a[mid]==target)
        {
            return mid;
        }
        else if(a[mid]>target)
        {
            end = mid-1;
        }
        else
        {
            start = mid + 1;
        }
    }
    return -1;
}
 
void swap(ll &x, ll &y) {
    ll temp = x; 
    x = y; 
    y = temp;
}
 
ll binpow(ll a, ll b) {
    ll res = 1;
    while (b > 0) {
        if (b & 1)
            res = (res * a)%998244353;
        a = (a * a)%998244353;
        b >>= 1;
    }
    return res%998244353;
}
 
ll factorial(ll n)
{
    ll ans = 1;
    for(int i=1; i<=n; ++i)
    {
        ans = ans*i;
    }
    return ans;
}
 
ll nCr(int n, int r)
{
    if(r>n)
    {
        return 0;
    }
    else if(r==0 || r==n)
    {
        return 1;
    }
    else
    {
        ll dp[n+1][r+1];
        for(int i=0; i<=n; ++i)
        {
            for(int j=0; j<=min(i,r); ++j)
            {
                if(j==i || j==0)
                {
                    dp[i][j] = 1;
                }
                else
                {
                    dp[i][j] = (dp[i-1][j-1] + dp[i-1][j]);
                }
            }
        }
        return dp[n][r];
    }
}
 
string decimal_to_binary_string(ll x)
{
    string s = "";
    // for(int i = 0; i < 30; ++i)
    while(x!=0)
    {
        int r = x%2;
        s += to_string(r);
        x = x/2;
    }
    reverse(s.begin(), s.end());
    return s; // s is the binary string for the decimal number x
}
 
string decimal_to_hexadecimal_string(ll x)
{
    string s = "";
    // for(int i = 1; i <= 31; ++i)
    while(x!=0)
    {
        int r = x%16;
        if(r <= 9)
        s += to_string(r);
        else
        {
            if(r==10)
            {
                s += 'A';
            }
            else if(r==11)
            {
                s += 'B';
            }
            else if(r==12)
            {
                s += 'C';
            }
            else if(r==13)
            {
                s += 'D';
            }
            else if(r==14)
            {
                s += 'E';
            }
            else if(r==15)
            {
                s += 'F';
            }
        }
        x = x/16;
    }
    reverse(s.begin(), s.end());
    return s; // s is the hexadecimal string for the decimal number x
}
 
ll binary_string_to_decimal(string s)
{
    reverse(s.begin(), s.end());
    ll ans = 0;
    for(int i = 0; i < s.length(); ++i)
    {
        if(s[i] == '1')
        {
            ans += binpow(2,i);
        }
    }
    return ans;
}
 
vector<int> dijkstra(vector<vector<pair<int,int>>>& adj, int n, int src)
{
    vector<int> dist(n+1, INT_MAX);
    dist[src] = 0;
    priority_queue<pair<int,int>> pq;
    pq.push({0,src});
    while(!pq.empty())
    {
        int u = pq.top().second;
        int d = pq.top().first;
        pq.pop();
        if(d > dist[u])
        {
            continue;
        }
        for(auto& v : adj[u])
        {
            if(dist[u]!=INT_MAX && dist[v.first] > dist[u] + v.second)
            {
                dist[v.first] = dist[u] + v.second;
                pq.push({-dist[v.first], v.first});
            }
        }
    }
    return dist;
}
 
ll sqrtDecomposition(vector<ll>& a, int l, int r) // give the value for 1 query
{
    int n = a.size();
    int len = (int)sqrt(n) + 1;
    vector<ll> b(len);
    for(int i = 0; i < n; ++i)
    {
        b[i/len] += a[i];
    }
 
    ll sum = 0;
 
    int c_l = l/len;
    int c_r = r/len;
    if(c_l == c_r)
    {
        for(int i = l; i <= r; ++i)
        {
            sum += a[i];
        }
        return sum;
    }
 
    for(int i = l; i <= (c_l + 1)*len - 1; ++i)
    {
        sum += a[i];
    }
    for(int i = c_l; i <= c_r - 1; ++i)
    {
        sum += b[i];
    }
    for(int i = c_r*len; i <= r; ++i)
    {
        sum += a[i];
    }
    return sum;
}
 
bool kahn(int V, vector<int>& in_degree, vector<vector<int>>& adj) // returns the topological sorting for the graph
{
    queue<int> pq;
	for(int i = 1; i <= V; ++i)
	{
	    if(in_degree[i] == 0)
	    {
	        pq.push(i);
	    }
	}
	vector<int> ans;
	while(!pq.empty())
	{
	    int u = pq.front();
	    pq.pop();
	    ans.push_back(u);
	    for(auto& v : adj[u])
	    {
            in_degree[v]--;
	        if(in_degree[v] == 0)
	        {
	            pq.push(v);
	        }
	    }
	}
	return ans.size() == V;
}
 
struct TrieNode
{
    TrieNode *links[26];
    bool flag = false; // tells if this is last character of the word or not
    bool containsKey(char ch) // checks if the children node having character ch has been initialized or not
    {
        if(links[ch - 'a'] != NULL)
        {
            return true;
        }
        return false;
    }
    void put(char ch, TrieNode* node) // assigns a node as the children of this node
    {
        links[ch-'a'] = node;
    }
 
    TrieNode* get(char ch) // gets the children node for value ch
    {
        return links[ch-'a'];
    }
    void setEnd()
    {
        flag = true;
    }
    bool getflag()
    {
        return flag;
    }
};
 
class Trie
{
    private:
        TrieNode* root;
    public:
        Trie()
        {
            root = new TrieNode();
        }
        // Inserting a new word 
        // a = 0, b = 1, c = 2, d = 3 and so on
        void insert(string word) // O(length of the word)
        {
            TrieNode* node = root; // start with the root node
            for(int i = 0; i < word.length(); ++i)
            {
                if(!node->containsKey(word[i]))
                {
                    node->put(word[i], new TrieNode()); // make a new TrieNode if the character do not exist.
                }
                node = node->get(word[i]); // move to the reference node of the current node
            }
            node->setEnd(); // set the flag = true for the last node
        }
 
        // Returs true if the word is in the trie -> Searching a word
        bool search(string word)
        {
            TrieNode* node = root;
            for(int i = 0; i < word.length(); ++i)
            {
                if(!node->containsKey(word[i]))
                {
                    return false;
                }
                node = node->get(word[i]);
            }
            if(node->getflag() == true)
            {
                return true;
            }
            return false;
        }
 
        // Returns true if there is a string with the given prefix in the trie
        bool startsWith(string prefix)
        {
            TrieNode* node = root;
            for(int i = 0; i < prefix.length(); ++i)
            {
                if(!node->containsKey(prefix[i]))
                {
                    return false;
                }
                node = node->get(prefix[i]);
            }
            return true;
        }
};

struct segment_tree
{
    int size;
    vector<pair<ll,ll>> v;
    ll NO_OPERATION;
    void init(int n)
    {
        size = 1;
        while(size < n)
        {
            size *= 2;
        }
        v.assign(2*size, {0,0});
        NO_OPERATION = -1;
    }

    void build(vector<ll>& a, int n, int x, int lx, int rx)
    {
        if(rx - lx == 1)
        {
            if(lx < n)
            {
                v[x] = {a[lx], a[lx]};
            }
        }
        else
        {
            int m = lx + (rx - lx)/2;
            build(a, n, 2*x + 1, lx, m);
            build(a, n, 2*x + 2, m, rx);
            v[x].second = operation(v[2*x + 1].second, v[2*x + 2].second);
        }
    }

    void build(vector<ll>& a, int n)
    {
        build(a, n, 0, 0, size);
    }

    ll operation(ll x, ll y)
    {

    }

    void propogate(int x)
    {
        v[2*x + 1].first += v[x].first;
        v[2*x + 2].first += v[x].first;
        v[x].first = 0;
    }

    void set(int l, int r, ll val, int x, int lx, int rx)
    {
        if(rx <= l || r <= lx)
        {
            return;
        }
        if(l <= lx && rx <= r)
        {
            v[x].first += val;
            return;
        }
        propogate(x);
        int m = (lx + rx)/2;
        if(r <= m)
        {
            set(l, r, val, 2*x + 1, lx, m);
        }
        else if(l >= m)
        {
            set(l, r, val, 2*x + 2, m, rx);
        }
        else
        {
            set(l, r, val, 2*x + 1, lx, m);
            set(l, r, val, 2*x + 2, m, rx);
        }
        v[x].second = (v[2*x + 1].first*(m - lx) + v[2*x + 2].first*(rx - m) + v[2*x + 1].second + v[2*x + 2].second);
    }

    void set(int l, int r, ll val)
    {
        set(l, r, val, 0, 0, size);
    }

    ll query(int l, int r, int x, int lx, int rx)
    {
        if(l <= lx && rx <= r)
        {
            return v[x].first*(rx - lx) + v[x].second;
        }

        int m = (lx + rx)/2;
        if(r <= m)
        {
            return (v[x].first*(m - lx) + query(l, r, 2*x + 1, lx, m));
        }
        else if(l >= m)
        {
            return (v[x].first*(rx - m) + query(l, r, 2*x + 2, m, rx));
        }
        else
        {
            ll ans1 = query(l, r, 2*x + 1, lx, m);
            ll ans2 = query(l, r, 2*x + 2, m, rx);
            return (v[x].first*(r - l) + ans1 + ans2);
        }
    }

    ll query(int l, int r)
    {
        return query(l, r, 0, 0, size);
    }
};

vector<ll> compute_hash_string(string s)
{
    ll p = 1000; // 31 for lowercase, 53 for upper + lower
    ll mutliplier = 1;
    ll multiplier = p;
    ll modulo = 1e9 + 9;
    int n = s.length();
    vector<ll> hash_value(n);
    for(int i = 0; i < n; ++i)
    {
        if(i == 0)
        {
            hash_value[i] = ((s[i] - 'a' + 1) + multiplier)%modulo;
            // multiplier *= p;
            // multiplier = multiplier%modulo;
        }
        else
        {
            hash_value[i] = (hash_value[i-1]*((s[i] - 'a' + 1) + multiplier))%modulo;
            // multiplier *= p;
            // multiplier = multiplier%modulo;
        }
    }
    return hash_value;
}

struct DSU {
    int n;
    vector<int> p;
    vector<int> size;
    void init(int sz)
    {
        n = sz;
        p.assign(n+1,0);
        size.assign(n+1,0);
        for(int i = 1; i <= n; ++i)
        {
            p[i] = i;
            size[i] = 1;
        }
    }
 
    void make_set(int v)
    {
        p[v] = v;
        size[v] = 1;
    }
 
    int get(int x)
    {
        if(x != p[x])
        {
            return p[x] = get(p[x]);
        }
        return x;
    }
 
    void union_set(int a, int b)
    {
        if(size[a] < size[b])
        {
            p[a] = b;
            size[b] += size[a];
        }
        else
        {
            p[b] = a;
            size[a] += size[b];
        }
    }
};

static bool cmp(const pair<int,int>& p1, const pair<int,int>& p2)
{
    return p1.first > p2.first;
}

int remove_edges(int node, vector<int>& degree, vector<vector<int>>& adj)
{
    for(auto& v : adj[node])
    {
        degree[v] -= 1;
    }
    degree[node] = 0;

    int ret = *max_element(degree.begin(), degree.end());
    for(auto& v : adj[node])
    {
        degree[v] += 1;
        degree[node] += 1;
    }
    return ret-1;
}

void solve()
{
    int n;
    cin>>n;

    int u,v;
    vector<vector<int>> adj(n+1);
    vector<int> degree(n+1, 0);

    rep(i,n-1)
    {
        cin>>u>>v;
        adj[u].push_back(v);
        adj[v].push_back(u);
        degree[u] += 1;
        degree[v] += 1;
    }

    vector<pair<int,int>> nd;
    for(int i = 1; i <= n; ++i)
    {
        nd.push_back({degree[i], i});
    }

    sort(nd.begin(), nd.end(), cmp);

    int ans1 = nd[0].first;

    if(nd[1].first == ans1)
    {
        ans1 += max(remove_edges(nd[0].second, degree, adj), remove_edges(nd[1].second, degree, adj));
    }
    else
    {
        for(auto& v : adj[nd[0].second])
        {
            degree[v] -= 1;
        }
        degree[nd[0].second] = 0;
        ans1 += *max_element(degree.begin(), degree.end()) - 1;
    }

    cout<<ans1<<"\n";
    
}
 
int main() {
    ios_base::sync_with_stdio(0);
    cin.tie(0); 
    cout.tie(0);
    // freopen("line_by_line_input.txt", "r", stdin);
    // freopen("line_by_line_output.txt", "w", stdout);
    int t = 1;
    cin>>t; // comment this line if number of test cases is not given as input
    for(int i=1; i<=t; ++i)
    {
        // cout<<"Case #"<<i<<": ";
        solve();
    }
}