Problem p03014 (C++)

Buggy submission (status: Runtime Error):
#include <bits/stdc++.h>

#define REP(i, n) for (int i = 0; i < n; i++)
#define FOR(i, n, m) for (int i = n; i < m; i++)
#define ll long long int

using namespace std;

struct UnionFind {
  vector<int> par; // par[i]が親を表す
  vector<int> _size; // _size[i]でそのノードの属しているサイズを返す

  // コンストラクタ
  UnionFind(int n) {
    _size = vector<int>(n);
    par = vector<int>(n);
    for (int i = 0; i < n; i++) {
      par[i] = i;
      _size[i] = 1;
    }
  }

  // データxの根を求める
  int root(int x) {
    if (par[x] == x)
      return x;
    return par[x] = root(par[x]); // 木構造の縮約を行っている
  }

  // xとyの親が違うとき、マージする。そのときyの根がxの根の子になる
  void merge(int x, int y) {
    int rootx = root(x);
    int rooty = root(y);
    if (rootx == rooty)
      return;
    par[rooty] = rootx;
    int s = _size[rooty] + _size[rootx];
    _size[rooty] = s;
    _size[rootx] = s;
  }

  // xの属している集団のサイズ
  int size(int x) { return _size[x]; }

  // 同じグループに属しているか
  bool isSame(int x, int y) { return root(x) == root(y); }
};

int main() {
  int h, w;
  bool map[2000][2000] = {};
  cin >> h >> w;
  UnionFind ufx(h * w - 1); // i*w + j
  UnionFind ufy(h * w - 1);
  REP(i, h) {
    string s;
    cin >> s;
    REP(j, s.length()) {
      if (s[j] == '.') {
        map[i][j] = true;
        if (i != 0) {
          if (map[i - 1][j]) {
            ufy.merge(i * w + j, (i - 1) * w + j);
          }
        }
        if (j != 0) {
          if (map[i][j - 1]) {
            ufx.merge(i * w + j, i * w + j - 1);
          }
        }
      }
    }
  }

  int result = 0;
  REP(i, h) {
    REP(j, w) {
      result = max(result, ufx.size(ufx.root(i * w + j)) +
                               ufy.size(ufy.root(i * w + j)) - 1);
    }
  }
  cout << result << endl;
}


Fixed submission:
#include <bits/stdc++.h>

#define REP(i, n) for (int i = 0; i < n; i++)
#define FOR(i, n, m) for (int i = n; i < m; i++)
#define ll long long int

using namespace std;

struct UnionFind {
  vector<int> par; // par[i]が親を表す
  vector<int> _size; // _size[i]でそのノードの属しているサイズを返す

  // コンストラクタ
  UnionFind(int n) {
    _size = vector<int>(n);
    par = vector<int>(n);
    for (int i = 0; i < n; i++) {
      par[i] = i;
      _size[i] = 1;
    }
  }

  // データxの根を求める
  int root(int x) {
    if (par[x] == x)
      return x;
    return par[x] = root(par[x]); // 木構造の縮約を行っている
  }

  // xとyの親が違うとき、マージする。そのときyの根がxの根の子になる
  void merge(int x, int y) {
    int rootx = root(x);
    int rooty = root(y);
    if (rootx == rooty)
      return;
    par[rooty] = rootx;
    int s = _size[rooty] + _size[rootx];
    _size[rooty] = s;
    _size[rootx] = s;
  }

  // xの属している集団のサイズ
  int size(int x) { return _size[x]; }

  // 同じグループに属しているか
  bool isSame(int x, int y) { return root(x) == root(y); }
};

int main() {
  int h, w;
  bool map[2000][2000] = {};
  cin >> h >> w;
  UnionFind ufx(h * w); // i*w + j
  UnionFind ufy(h * w);
  REP(i, h) {
    string s;
    cin >> s;
    REP(j, s.length()) {
      if (s[j] == '.') {
        map[i][j] = true;
        if (i != 0) {
          if (map[i - 1][j]) {
            ufy.merge(i * w + j, (i - 1) * w + j);
          }
        }
        if (j != 0) {
          if (map[i][j - 1]) {
            ufx.merge(i * w + j, i * w + j - 1);
          }
        }
      }
    }
  }

  int result = 0;
  REP(i, h) {
    REP(j, w) {
      result = max(result, ufx.size(ufx.root(i * w + j)) +
                               ufy.size(ufy.root(i * w + j)) - 1);
    }
  }
  cout << result << endl;
}