Problem p03157 (C++)

Buggy submission (status: Runtime Error):
#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <deque>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

using std::cerr;
using std::cin;
using std::cout;
using std::endl;

// Manages Union-Find Forest.
class UnionFindForest {
  std::vector<int> parent_;
  std::vector<int> rank_;
  std::vector<int> size_;

public:
  // Initialize forest.
  // parent_[i]=i, rank_[i]=0, size_[i]=1.
  UnionFindForest(const int &n);
  // Get the number of the root of the node q.
  int Root(const int &q);
  // Return true if the roots of x and y is same.
  bool IsSame(const int &x, const int &y);
  // Unite the tree x and tree y.
  void Unite(int x, int y);
  // Get the number of nodes which are the same group as node q.
  int Size(const int &q);
};
UnionFindForest::UnionFindForest(const int &n) {
  parent_.resize(n);
  rank_.resize(n);
  size_.resize(n);
  for (int i = 0; i < n; i++) {
    parent_[i] = i;
    rank_[i] = 0;
    size_[i] = 1;
  }
}
int UnionFindForest::Size(const int &q) { return size_[Root(q)]; }

int UnionFindForest::Root(const int &q) {
  if (parent_[q] == q) {
    return q;
  } else {
    return parent_[q] = Root(parent_[q]);
  }
}

bool UnionFindForest::IsSame(const int &x, const int &y) {
  return Root(x) == Root(y);
}

void UnionFindForest::Unite(int x, int y) {
  x = Root(x);
  y = Root(y);
  if (x == y)
    return;
  if (rank_[x] < rank_[y]) {
    parent_[x] = y;
    size_[y] += size_[x];
    size_[x] = 0;

  } else {
    parent_[y] = x;
    size_[x] += size_[y];
    size_[y] = 0;
    if (rank_[x] == rank_[y])
      rank_[x]++;
  }
}

int main(void) {
  cout << std::fixed << std::setprecision(10);
  cin.tie(0);
  std::ios::sync_with_stdio(false);

  int h, w;
  cin >> h >> w;
  // std::map<std::pair<int,int>,int> node_hash;
  // std::map<int,std::pair<int,int>> map_hash;
  char map[410][410];
  for (int c = 0; c <= w + 1; c++) {
    map[0][c] = '@';
    map[h + 1][c] = '@';
  }
  for (int r = 1; r <= h; r++) {
    map[r][0] = '@';
    std::string s;
    cin >> s;
    for (int c = 1; c <= w; c++) {
      map[r][c] = s[c - 1];
    }
    map[r][w + 1] = '@';
  }

  // int node_num=0;
  // for(int r=1;r<=h;r++){
  //   for(int c=1;c<=w;c++){
  //     node_hash[std::make_pair(r,c)]=node_num;
  //     map_hash[node_num]=std::make_pair(r,c);
  //     node_num++;
  //
  //   }
  // }

  UnionFindForest uf(h * w + 10);

  for (int r = 1; r <= h; r++) {
    for (int c = 1; c <= w; c++) {
      for (int vr = -1; vr <= 1; vr++) {
        for (int vc = -1; vc <= 1; vc++) {
          if ((vr == 0 && vc != 0) || (vr != 0 && vc == 0)) {

            if (map[r + vr][c + vc] != '@' &&
                map[r][c] != map[r + vr][c + vc]) {
              uf.Unite((r - 1) * w + c - 1, (r + vr - 1) * w + c + vc - 1);
            }
          }
        }
      }
    }
  }

  int result = 0;
  int w_count[1610] = {}, b_count[1610] = {};
  for (int node = 0; node < h * w; node++) {
    if (map[node / w + 1][node % w + 1] == '#') {
      b_count[uf.Root(node)]++;
    } else {
      w_count[uf.Root(node)]++;
    }
  }

  for (int i = 0; i < h * w; i++) {
    result += b_count[i] * w_count[i];
  }

  cout << result << endl;

  return 0;
}


Fixed submission:
#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <deque>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

using std::cerr;
using std::cin;
using std::cout;
using std::endl;

// Manages Union-Find Forest.
class UnionFindForest {
  std::vector<int> parent_;
  std::vector<int> rank_;
  std::vector<int> size_;

public:
  // Initialize forest.
  // parent_[i]=i, rank_[i]=0, size_[i]=1.
  UnionFindForest(const int &n);
  // Get the number of the root of the node q.
  int Root(const int &q);
  // Return true if the roots of x and y is same.
  bool IsSame(const int &x, const int &y);
  // Unite the tree x and tree y.
  void Unite(int x, int y);
  // Get the number of nodes which are the same group as node q.
  int Size(const int &q);
};
UnionFindForest::UnionFindForest(const int &n) {
  parent_.resize(n);
  rank_.resize(n);
  size_.resize(n);
  for (int i = 0; i < n; i++) {
    parent_[i] = i;
    rank_[i] = 0;
    size_[i] = 1;
  }
}
int UnionFindForest::Size(const int &q) { return size_[Root(q)]; }

int UnionFindForest::Root(const int &q) {
  if (parent_[q] == q) {
    return q;
  } else {
    return parent_[q] = Root(parent_[q]);
  }
}

bool UnionFindForest::IsSame(const int &x, const int &y) {
  return Root(x) == Root(y);
}

void UnionFindForest::Unite(int x, int y) {
  x = Root(x);
  y = Root(y);
  if (x == y)
    return;
  if (rank_[x] < rank_[y]) {
    parent_[x] = y;
    size_[y] += size_[x];
    size_[x] = 0;

  } else {
    parent_[y] = x;
    size_[x] += size_[y];
    size_[y] = 0;
    if (rank_[x] == rank_[y])
      rank_[x]++;
  }
}

int main(void) {
  cout << std::fixed << std::setprecision(10);
  cin.tie(0);
  std::ios::sync_with_stdio(false);

  int h, w;
  cin >> h >> w;
  // std::map<std::pair<int,int>,int> node_hash;
  // std::map<int,std::pair<int,int>> map_hash;
  char map[410][410];
  for (int c = 0; c <= w + 1; c++) {
    map[0][c] = '@';
    map[h + 1][c] = '@';
  }
  for (int r = 1; r <= h; r++) {
    map[r][0] = '@';
    std::string s;
    cin >> s;
    for (int c = 1; c <= w; c++) {
      map[r][c] = s[c - 1];
    }
    map[r][w + 1] = '@';
  }

  // int node_num=0;
  // for(int r=1;r<=h;r++){
  //   for(int c=1;c<=w;c++){
  //     node_hash[std::make_pair(r,c)]=node_num;
  //     map_hash[node_num]=std::make_pair(r,c);
  //     node_num++;
  //
  //   }
  // }

  UnionFindForest uf(h * w + 10);

  for (int r = 1; r <= h; r++) {
    for (int c = 1; c <= w; c++) {
      for (int vr = -1; vr <= 1; vr++) {
        for (int vc = -1; vc <= 1; vc++) {
          if ((vr == 0 && vc != 0) || (vr != 0 && vc == 0)) {

            if (map[r + vr][c + vc] != '@' &&
                map[r][c] != map[r + vr][c + vc]) {
              uf.Unite((r - 1) * w + c - 1, (r + vr - 1) * w + c + vc - 1);
            }
          }
        }
      }
    }
  }

  int64_t result = 0;
  int64_t w_count[161000] = {}, b_count[161000] = {};
  for (int node = 0; node < h * w; node++) {
    if (map[node / w + 1][node % w + 1] == '#') {
      b_count[uf.Root(node)]++;
    } else {
      w_count[uf.Root(node)]++;
    }
  }

  for (int i = 0; i < h * w; i++) {
    result += b_count[i] * w_count[i];
  }

  cout << result << endl;

  return 0;
}