Problem p03575 (C++)

Buggy submission (status: Runtime Error):
#include <algorithm>
#include <iostream>
#include <vector>

template <typename T> class UnionFindTree {
public:
  UnionFindTree(T size = 0) {
    if (size == 0)
      return;

    unitedSize.resize(size + 1, 1);
    rank.resize(size + 1);
    parents.resize(size + 1);
    for (T i = 0; i < size; ++i) {
      // 最初は自分自身が親
      parents[i] = i;
      rank[i] = 0;
    }
  }

  // 一方の根をもう一方の根の子にする
  bool Union(T x, T y) {
    x = FindRoot(x);
    y = FindRoot(y);
    if (x == y)
      return false;

    // ノードごとの rank を記憶しておき rank が低い方を高い方の子にする
    // 例: 6-4-7 / 2-5, Union(6, 2)の場合 2 を 6 の子にする
    if (rank[x] < rank[y]) {
      parents[x] = y;
      unitedSize[y] += unitedSize[x];
      // 子を増やした方の rank を更新
      if (rank[y] == rank[x])
        rank[y]++;
    } else {
      parents[y] = x;
      unitedSize[x] += unitedSize[y];
      // 子を増やした方の rank を更新
      if (rank[x] == rank[y])
        rank[x]++;
    }
  }

  T FindRoot(T x) {
    if (parents[x] == x)
      return x;

    // root にたどり着くまで
    while (parents[x] != x) {
      // x の親の親 を x の親とする
      T parent = parents[x];
      parents[x] = parents[parent];
      x = parents[x];
    }

    return x;
  }

  bool IsUnited(T a, T b) { return FindRoot(a) == FindRoot(b); }

  T GetUnitedSize(T x) { return unitedSize[FindRoot(x)]; }

private:
  std::vector<T> parents;
  std::vector<T> rank;
  std::vector<T> unitedSize;
};

int main() {
  int N, M;
  std::cin >> N >> M;

  std::vector<std::pair<int, int>> connection(M);
  UnionFindTree<int> intactTree(N);
  for (int i = 0; i < M; ++i) {
    int ai, bi;
    std::cin >> ai >> bi;
    intactTree.Union(ai, bi);
    connection[i] = {ai, bi};
  }

  int result = 0;
  for (int i = 0; i < M; ++i) {
    UnionFindTree<int> brokenTree(N);
    for (int j = 0; j < M; ++j) {
      // i番目のconnectionはなかったことにする
      if (i == j)
        continue;

      brokenTree.Union(connection[j].first, connection[j].second);
    }

    if (brokenTree.GetUnitedSize(i) < intactTree.GetUnitedSize(i))
      result++;
  }
  std::cout << result;
}

Fixed submission:
#include <algorithm>
#include <iostream>
#include <vector>

template <typename T> class UnionFindTree {
public:
  UnionFindTree(T size = 0) {
    if (size == 0)
      return;

    unitedSize.resize(size + 1, 1);
    rank.resize(size + 1);
    parents.resize(size + 1);
    for (T i = 0; i < size; ++i) {
      // 最初は自分自身が親
      parents[i] = i;
      rank[i] = 0;
    }
  }

  // 一方の根をもう一方の根の子にする
  bool Union(T x, T y) {
    x = FindRoot(x);
    y = FindRoot(y);
    if (x == y)
      return false;

    // ノードごとの rank を記憶しておき rank が低い方を高い方の子にする
    // 例: 6-4-7 / 2-5, Union(6, 2)の場合 2 を 6 の子にする
    if (rank[x] < rank[y]) {
      parents[x] = y;
      unitedSize[y] += unitedSize[x];
      // 子を増やした方の rank を更新
      if (rank[y] == rank[x])
        rank[y]++;
    } else {
      parents[y] = x;
      unitedSize[x] += unitedSize[y];
      // 子を増やした方の rank を更新
      if (rank[x] == rank[y])
        rank[x]++;
    }
  }

  T FindRoot(T x) {
    if (parents[x] == x)
      return x;

    // root にたどり着くまで
    while (parents[x] != x) {
      // x の親の親 を x の親とする
      T parent = parents[x];
      parents[x] = parents[parent];
      x = parents[x];
    }

    return x;
  }

  bool IsUnited(T a, T b) { return FindRoot(a) == FindRoot(b); }

  T GetUnitedSize(T x) { return unitedSize[FindRoot(x)]; }

private:
  std::vector<T> parents;
  std::vector<T> rank;
  std::vector<T> unitedSize;
};

int main() {
  int N, M;
  std::cin >> N >> M;

  std::vector<std::pair<int, int>> connection(M);
  UnionFindTree<int> intactTree(N);
  for (int i = 0; i < M; ++i) {
    int ai, bi;
    std::cin >> ai >> bi;
    intactTree.Union(ai, bi);
    connection[i] = {ai, bi};
  }

  int result = 0;
  for (int i = 0; i < M; ++i) {
    UnionFindTree<int> brokenTree(N);
    for (int j = 0; j < M; ++j) {
      // i番目のconnectionはなかったことにする
      if (i == j)
        continue;

      brokenTree.Union(connection[j].first, connection[j].second);
    }

    if (brokenTree.GetUnitedSize(0) < N)
      result++;
  }
  std::cout << result;
}