Problem p03157 (C++)

Buggy submission (status: Time Limit Exceeded):
#include "bits/stdc++.h"
using namespace std;
using ll = long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using vi = vector<int>;
using vl = vector<ll>;
using vvi = vector<vi>;
using vvl = vector<vl>;
const ll INF = 1LL << 60;
const ll MOD = INF; // disable
template <class T> bool chmax(T &a, const T &b) {
  return (a < b) ? (a = b, 1) : 0;
}
template <class T> bool chmin(T &a, const T &b) {
  return (b < a) ? (a = b, 1) : 0;
}
template <class C> void print(const C &c, std::ostream &os = std::cout) {
  std::copy(std::begin(c), std::end(c),
            std::ostream_iterator<typename C::value_type>(os, " "));
  os << std::endl;
}

struct UnionFind {
  vector<int> rank, parent, size;

  // +1 for 1-indexed nodes
  UnionFind(int n) : rank(n + 1, 0), parent(n + 1), size(n + 1, 1) {
    iota(parent.begin(), parent.end(), 0); // parent is itself
  }
  int root(int x) {
    if (x != parent[x]) {
      parent[x] = root(parent[x]);
    }
    return parent[x];
  }
  bool isSame(int x, int y) { return root(x) == root(y); }
  bool unite(int x, int y) { return link(root(x), root(y)); }
  bool link(int x, int y) {
    if (x == y)
      return false;
    if (rank[x] > rank[y]) {
      parent[y] = x;
      size[x] += size[y];
    } else {
      parent[x] = y;
      size[y] += size[x];
      if (rank[x] == rank[y]) {
        rank[y]++;
      }
    }
    return true;
  }
  int getSize(int x) { return size[root(x)]; }
};

struct Combination {
  vector<ll> fac, finv, inv;

  Combination(ll maxN) {
    maxN += 100; // for safety
    fac.resize(maxN + 1);
    finv.resize(maxN + 1);
    inv.resize(maxN + 1);
    fac[0] = fac[1] = 1;
    finv[0] = finv[1] = 1;
    inv[1] = 1;
    for (ll i = 2; i <= maxN; ++i) {
      fac[i] = fac[i - 1] * i % MOD;
      inv[i] = MOD - inv[MOD % i] * (MOD / i) % MOD;
      finv[i] = finv[i - 1] * inv[i] % MOD;
    }
  }
  ll operator()(ll n, ll k) {
    if (n < k)
      return 0;
    if (n < 0 || k < 0)
      return 0;
    return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD;
  }
};

int main() {
  int h, w;
  cin >> h >> w;
  int n = h * w;
  vector<string> s(h);
  for (int i = 0; i < h; ++i) {
    cin >> s[i];
  }
  auto idx = [&](int y, int x) { return y * w + x; };
  const int dx[4] = {-1, 1, 0, 0};
  const int dy[4] = {0, 0, -1, 1};
  auto inside = [&](int y, int x) {
    return 0 <= y && y < h && 0 <= x && x < w;
  };
  UnionFind uf(n);
  map<int, pii> cnt; // par, bl, wh
  for (int i = 0; i < h; ++i) {
    for (int j = 0; j < w; ++j) {
      for (int k = 0; k < 4; ++k) {
        int ny = i + dy[k];
        int nx = j + dx[k];
        if (inside(ny, nx)) {
          if (s[i][j] != s[ny][nx]) {
            uf.unite(idx(i, j), idx(ny, nx));
          }
        }
      }
    }
  }
  ll ret = 0;
  for (int i = 0; i < h * w; ++i) {
    int bl = 0;
    int wh = 0;
    for (int y = 0; y < h; ++y) {
      for (int x = 0; x < w; ++x) {
        if (uf.parent[idx(y, x)] == i) {
          if (s[y][x] == '.')
            wh++;
          else
            bl++;
        }
      }
    }
    ret += bl * wh;
  }
  cout << ret << "\n";
  return 0;
}

Fixed submission:
#include "bits/stdc++.h"
using namespace std;
using ll = long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using vi = vector<int>;
using vl = vector<ll>;
using vvi = vector<vi>;
using vvl = vector<vl>;
const ll INF = 1LL << 60;
const ll MOD = INF; // disable
template <class T> bool chmax(T &a, const T &b) {
  return (a < b) ? (a = b, 1) : 0;
}
template <class T> bool chmin(T &a, const T &b) {
  return (b < a) ? (a = b, 1) : 0;
}
template <class C> void print(const C &c, std::ostream &os = std::cout) {
  std::copy(std::begin(c), std::end(c),
            std::ostream_iterator<typename C::value_type>(os, " "));
  os << std::endl;
}

struct UnionFind {
  vector<int> rank, parent, size;

  // +1 for 1-indexed nodes
  UnionFind(int n) : rank(n + 1, 0), parent(n + 1), size(n + 1, 1) {
    iota(parent.begin(), parent.end(), 0); // parent is itself
  }
  int root(int x) {
    if (x != parent[x]) {
      parent[x] = root(parent[x]);
    }
    return parent[x];
  }
  bool isSame(int x, int y) { return root(x) == root(y); }
  bool unite(int x, int y) { return link(root(x), root(y)); }
  bool link(int x, int y) {
    if (x == y)
      return false;
    if (rank[x] > rank[y]) {
      parent[y] = x;
      size[x] += size[y];
    } else {
      parent[x] = y;
      size[y] += size[x];
      if (rank[x] == rank[y]) {
        rank[y]++;
      }
    }
    return true;
  }
  int getSize(int x) { return size[root(x)]; }
};

struct Combination {
  vector<ll> fac, finv, inv;

  Combination(ll maxN) {
    maxN += 100; // for safety
    fac.resize(maxN + 1);
    finv.resize(maxN + 1);
    inv.resize(maxN + 1);
    fac[0] = fac[1] = 1;
    finv[0] = finv[1] = 1;
    inv[1] = 1;
    for (ll i = 2; i <= maxN; ++i) {
      fac[i] = fac[i - 1] * i % MOD;
      inv[i] = MOD - inv[MOD % i] * (MOD / i) % MOD;
      finv[i] = finv[i - 1] * inv[i] % MOD;
    }
  }
  ll operator()(ll n, ll k) {
    if (n < k)
      return 0;
    if (n < 0 || k < 0)
      return 0;
    return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD;
  }
};

int main() {
  int h, w;
  cin >> h >> w;
  int n = h * w;
  vector<string> s(h);
  for (int i = 0; i < h; ++i) {
    cin >> s[i];
  }
  auto idx = [&](int y, int x) { return y * w + x; };
  const int dx[4] = {-1, 1, 0, 0};
  const int dy[4] = {0, 0, -1, 1};
  auto inside = [&](int y, int x) {
    return 0 <= y && y < h && 0 <= x && x < w;
  };
  UnionFind uf(n);
  map<int, pii> cnt; // par, bl, wh
  for (int i = 0; i < h; ++i) {
    for (int j = 0; j < w; ++j) {
      for (int k = 0; k < 4; ++k) {
        int ny = i + dy[k];
        int nx = j + dx[k];
        if (inside(ny, nx)) {
          if (s[i][j] != s[ny][nx]) {
            uf.unite(idx(i, j), idx(ny, nx));
          }
        }
      }
    }
  }
  ll ret = 0;
  map<int, vector<pii>> roots;
  for (int y = 0; y < h; ++y) {
    for (int x = 0; x < w; ++x) {
      roots[uf.root(idx(y, x))].emplace_back(y, x);
    }
  }
  for (auto &p : roots) {
    ll bl = 0;
    ll wh = 0;
    for (auto &yx : p.second) {
      int y = yx.first;
      int x = yx.second;
      if (s[y][x] == '.')
        wh++;
      else
        bl++;
    }
    ret += bl * wh;
  }
  cout << ret << "\n";
  return 0;
}