Problem: 2063C - Remove Exactly Two
Language: C++17 (GCC 7-32)

Previous submission (verdict: Wrong answer on test 12):
#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;
}
bool canClearAll(const vector<pi> &caves, ll mid) {
    for (size_t i = 0; i < caves.size(); i++) {
        if(mid < caves[i].first)
            return false;
        mid += caves[i].second;
    }
    return true;
}

bool comp(const pi &a, const pi &b) {
    if(a.first != b.first)
        return a.first < b.first;
    return a.second > b.second;
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
 
    int tc;
    cin >> tc;
    while(tc--) {
        int n;
        cin >> n;
        
        vi in(n + 1, 0);
        vector<vi> adj(n + 1);
        vector<pair<int, int>> edges;
        
        for (int i = 0; i < n - 1; i++) {
            int u, v;
            cin >> u >> v;
            adj[u].pb(v);
            adj[v].pb(u);
            in[u]++;
            in[v]++;
            edges.push_back({u, v});
        }
        
        if(n <= 2) {
            cout << 0 << "\n";
            continue;
        }
        
        // Candidate 1: consider adjacent pairs.
        // For every edge (u,v) we can achieve: in[u] + in[v] - 2.
        int candidate1 = 0;
        for(auto &e : edges) {
            int u = e.first, v = e.second;
            candidate1 = max(candidate1, in[u] + in[v] - 2);
        }
        
        // Candidate 2: consider non-adjacent pairs.
        // For a non-adjacent pair (u,v), the result is in[u] + in[v] - 1.
        vector<pair<int, int>> degs; // (degree, vertex)
        for (int i = 1; i <= n; i++) {
            degs.push_back({in[i], i});
        }
        sort(degs.begin(), degs.end(), greater<pair<int, int>>());
 
        // Build neighbor sets for quick checking of adjacency.
        vector<unordered_set<int>> neigh(n + 1);
        for (int i = 1; i <= n; i++) {
            for(auto nb : adj[i])
                neigh[i].insert(nb);
        }
 
        int candidate2 = 0;
        int lim = min((int)degs.size(),(int) 50); // only check top 50 vertices
        for (int i = 0; i < lim; i++) {
            for (int j = i + 1; j < lim; j++) {
                int u = degs[i].second, v = degs[j].second;
                // Only consider if u and v are NOT adjacent.
                if(neigh[u].find(v) == neigh[u].end()) {
                    candidate2 = max(candidate2, in[u] + in[v] - 1);
                }
            }
        }
 
        int ans = max(candidate1, candidate2);
        cout << ans << "\n";
    }
    
    return 0;
}


Submission (verdict: Accepted):
#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;
}