Problem p02573 (C++) — buggy submission, verdict: Time Limit Exceeded

#include <bits/stdc++.h>
using namespace std;
#pragma GCC optimize("O0")
typedef long long int ll;
typedef long double ld;
#define rep(i, n) for (ll i = 0; i < (n); ++i)
const ll mod = 1e9 + 7;
const ll INF = 1e18;
#define All(a) (a).begin(), (a).end()
#define Pi acos(-1)
// 素集合データ構造
struct UnionFind {
  // par[i]：データiが属する木の親の番号。i ==
  // par[i]のとき、データiは木の根ノードである
  vector<int> par;
  // sizes[i]：根ノードiの木に含まれるデータの数。iが根ノードでない場合は無意味な値となる
  vector<int> sizes;

  UnionFind(int n) : par(n), sizes(n, 1) {
    // 最初は全てのデータiがグループiに存在するものとして初期化
    rep(i, n) par[i] = i;
  }

  // データxが属する木の根を得る
  int find(int x) {
    if (x == par[x])
      return x;
    return par[x] = find(par[x]); // 根を張り替えながら再帰的に根ノードを探す
  }

  // 2つのデータx, yが属する木をマージする
  void unite(int x, int y) {
    // データの根ノードを得る
    x = find(x);
    y = find(y);

    // 既に同じ木に属しているならマージしない
    if (x == y)
      return;

    // xの木がyの木より大きくなるようにする
    if (sizes[x] < sizes[y])
      swap(x, y);

    // xがyの親になるように連結する
    par[y] = x;
    sizes[x] += sizes[y];
    // sizes[y] = 0;  // sizes[y]は無意味な値となるので0を入れておいてもよい
  }

  // 2つのデータx, yが属する木が同じならtrueを返す
  bool same(int x, int y) { return find(x) == find(y); }

  // データxが含まれる木の大きさを返す
  ll size(ll x) { return sizes[find(x)]; }
};

int main() {
  cin.tie(0);
  ios_base::sync_with_stdio(false);
  cout << setprecision(15) << fixed;
  chrono::system_clock::time_point start, end;
  start = chrono::system_clock::now();

  ll n, m;
  cin >> n >> m;
  UnionFind tree(n);
  ll ans = 0;
  rep(i, m) {
    ll x, y;
    cin >> x >> y;
    tree.unite(x - 1, y - 1);
  }
  rep(i, n) { ans = max(ans, tree.size(i)); }
  cout << ans << '\\n';

  end = chrono::system_clock::now();
  auto elapsed =
      chrono::duration_cast<chrono::milliseconds>(end - start).count();
  cerr << elapsed << "ms" << '\\n';
}

Error: TLE

Fixed submission:

#include <bits/stdc++.h>
using namespace std;
#pragma GCC optimize("O0")
typedef long long int ll;
typedef long double ld;
#define rep(i, n) for (ll i = 0; i < (n); ++i)
const ll mod = 1e9 + 7;
const ll INF = 1e18;
#define All(a) (a).begin(), (a).end()
#define Pi acos(-1)

struct UnionFind {
  vector<int> par; // par[i]:iの親の番号　(例) par[3] = 2 : 3の親が2

  UnionFind(int N) : par(N) { // 最初は全てが根であるとして初期化
    for (int i = 0; i < N; i++)
      par[i] = i;
  }

  int root(int x) { // データxが属する木の根を再帰で得る：root(x) = {xの木の根}
    if (par[x] == x)
      return x;
    return par[x] = root(par[x]);
  }

  void unite(int x, int y) { // xとyの木を併合
    int rx = root(x);        // xの根をrx
    int ry = root(y);        // yの根をry
    if (rx == ry)
      return; // xとyの根が同じ(=同じ木にある)時はそのまま
    par[rx] =
        ry; // xとyの根が同じでない(=同じ木にない)時：xの根rxをyの根ryにつける
  }

  bool same(int x, int y) { // 2つのデータx, yが属する木が同じならtrueを返す
    int rx = root(x);
    int ry = root(y);
    return rx == ry;
  }
};

int main() {
  cin.tie(0);
  ios_base::sync_with_stdio(false);
  cout << setprecision(15) << fixed;
  chrono::system_clock::time_point start, end;
  start = chrono::system_clock::now();

  ll n, m;
  cin >> n >> m;
  UnionFind tree(n);
  ll ans = 0;
  rep(i, m) {
    ll x, y;
    cin >> x >> y;
    tree.unite(x - 1, y - 1);
  }
  vector<bool> q(n, true);
  rep(i, n) {
    ll tmp = 1;
    for (ll j = i + 1; j < n; ++j) {
      if (tree.same(i, j) && q[j] == true) {
        q[j] = false;
        ++tmp;
      }
    }
    ans = max(ans, tmp);
  }
  cout << ans << '\\n';

  end = chrono::system_clock::now();
  auto elapsed =
      chrono::duration_cast<chrono::milliseconds>(end - start).count();
  cerr << elapsed << "ms" << '\\n';
}