[CF] C. Remove Exactly Two - Codeforces Round 1000 (Div. 2)
Solutions Codeforces 贪心 Med-
Lastmod: 2025-01-22 周三 22:07:17

https://codeforces.com/contest/2063/problem/C

题目大意

给出一棵 $n \ (2 \le n \le 2 \times 10^5)$ 个点的树,从中删掉 $2$ 个不同的点,问删完之后最多有多少个联通分量。

简要题解

首先 $n = 2, 3$ 是平凡的,单独处理就好。

其他情况,我们应该尽量删掉两个度最大的节点。但注意要处理两个点可能相邻的情况。

如果有 $3$ 个或以上度最大的节点,则至少有一对的是不相邻的,直接选这一对即可。

如果只有 $2$ 个,则这俩一定是最优的,但相邻的时候会少产生一个联通分量。

如果只有 $1$ 个,则我们还需要选取一个次大的点,尽量选一个不与最大点相邻的次大点。

复杂度

$T$:$O(n \log n)$ (log 来自于 set 也是可以去掉的。比如直接遍历所有次大点也行)。

$S$:$O(n)$

代码实现

#include <bits/stdc++.h>
using namespace std;

int io_=[](){ ios::sync_with_stdio(false); cin.tie(nullptr); return 0; }();

using LL = long long;
using ULL = unsigned long long;
using LD = long double;
using PII = pair<int, int>;
using VI = vector<int>;
using MII = map<int, int>;

template<typename T> void cmin(T &x,const T &y) { if(y<x) x=y; }
template<typename T> void cmax(T &x,const T &y) { if(x<y) x=y; }
template<typename T> bool ckmin(T &x,const T &y) { 
    return y<x ? (x=y, true) : false; }
template<typename T> bool ckmax(T &x,const T &y) { 
    return x<y ? (x=y, true) : false; }
template<typename T> void cmin(T &x,T &y,const T &z) {// x<=y<=z 
    if(z<x) { y=x; x=z; } else if(z<y) y=z; }
template<typename T> void cmax(T &x,T &y,const T &z) {// x>=y>=z
    if(x<z) { y=x; x=z; } else if(y<z) y=z; }

// mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
// mt19937_64 rnd_64(chrono::system_clock::now().time_since_epoch().count());

/*
---------1---------2---------3---------4---------5---------6---------7---------
1234567890123456789012345678901234567890123456789012345678901234567890123456789
*/

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

  int u, v;
  vector<vector<int>> g(n);
  for (int i = 1; i < n; i++) {
    cin >> u >> v; u--; v--;
    g[u].push_back(v);
    g[v].push_back(u);
  }

  if (n == 2) {
    cout << "0\n";
    return;
  }
  if (n == 3) {
    cout << "1\n";
    return;
  }
  
  vector<int> mxid, mx2id;
  for (int i = 0; i < n; i++) {
    if (mxid.empty()) {
      mxid.push_back(i);
      continue;
    }
    if (g[mxid[0]].size() == g[i].size()) {
      mxid.push_back(i);
    } else if (g[mxid[0]].size() < g[i].size()) {
      mx2id = mxid;
      mxid.clear();
      mxid.push_back(i);
    } else {
      if (mx2id.empty()) {
        mx2id.push_back(i);
      } else if (g[mx2id[0]].size() < g[i].size()) {
        mx2id.clear();
        mx2id.push_back(i);
      } else if (g[mx2id[0]].size() == g[i].size()) {
        mx2id.push_back(i);
      }
    }
  }

  int ans = g[mxid[0]].size();
  if ((int)mxid.size() > 2) {
    ans += g[mxid[0]].size() - 1;
  } else if ((int)mxid.size() == 2) {
    ans += g[mxid[0]].size() - 1;
    for (int v : g[mxid[0]]) {
      if (v == mxid[1]) {
        ans--;
        break;
      }
    }
  } else {
    ans += g[mx2id[0]].size() - 1;

    set<int> se;
    int cnt = 0;
    for (int i : mx2id) se.insert(i);
    for (int v : g[mxid[0]]) {
      if (se.count(v)) cnt++;
    }
    if (cnt == (int)mx2id.size()) {
      ans--;
    }
  }

  cout << ans << '\n';
}

int main() {
  int t = 1; 
  cin >> t;
  while (t--) {
    solve();
  }
  return 0;
}
Prev: [CF] D. Game With Triangles - Codeforces Round 1000 (Div. 2)
Next: [CF] B. Subsequence Update - Codeforces Round 1000 (Div. 2)