Problem p02579 (C++)

Buggy submission (status: Time Limit Exceeded):
#include <bits/stdc++.h>
#define rep(i, n, m) for (int i = (n); i < (m); i++)
#define rrep(i, n, m) for (int i = (n)-1; i >= (m); i--)
#define pvec(vec)                                                              \
  {                                                                            \
    for (auto v : vec)                                                         \
      cout << v << ' ';                                                        \
    cout << endl;                                                              \
  }
#define pivec(vec)                                                             \
  {                                                                            \
    rep(i, 0, vec.size()) cout << i << ':' << vec[i] << ' ';                   \
    cout << endl;                                                              \
  }

using namespace std;
using ll = long long;

int H, W;

struct UnionFind {
  int n;
  vector<int> parent;
  vector<int> rank;
  UnionFind(int _n) : n(_n) {
    parent.assign(n, -1);
    rank.assign(n, 1);
  }

  int find(int i) {
    if (parent[i] == -1)
      return i;
    else
      return parent[i] = find(parent[i]);
  }

  void unite(int i, int j) {
    i = find(i);
    j = find(j);

    if (i == j)
      return;

    if (rank[i] == rank[j]) {
      parent[j] = i;
      ++rank[i];
    } else {
      if (rank[i] < rank[j])
        swap(i, j);
      parent[j] = i;
    }
  }

  bool is_same(int i, int j) { return find(i) == find(j); }
};

void connect(int th, int tw, int sh, int sw, UnionFind &uf,
             vector<string> grid) {
  if (sh < 0 or sh >= H)
    return;
  if (sw < 0 or sw >= W)
    return;
  if (grid[th][tw] == '#')
    return;
  if (grid[sh][sw] == '#')
    return;
  uf.unite(W * th + tw, W * sh + sw);
}

int main() {
  cin >> H >> W;
  int Ch, Cw, Dh, Dw;
  cin >> Ch >> Cw;
  cin >> Dh >> Dw;

  --Ch, --Cw;
  --Dh, --Dw;

  vector<string> grid(H);
  rep(i, 0, H) cin >> grid[i];

  UnionFind uf(H * W);

  rep(h, 0, H) rep(w, 0, W) {
    connect(h, w, h - 1, w, uf, grid);
    connect(h, w, h, w - 1, uf, grid);
    connect(h, w, h + 1, w, uf, grid);
    connect(h, w, h, w + 1, uf, grid);
  }

  // make graph
  vector<set<int>> edge(H * W, set<int>());
  rep(h, 0, H) rep(w, 0, W) {
    if (grid[h][w] == '#')
      continue;

    int s = uf.find(h * W + w);
    // printf("h: %d, w: %d, s: %d\n", h, w, s);

    rep(dh, -2, 3) rep(dw, -2, 3) {
      int th = h + dh;
      int tw = w + dw;

      if (th < 0 or th >= H)
        continue;
      if (tw < 0 or tw >= W)
        continue;
      if (grid[th][tw] == '#')
        continue;

      int t = uf.find(th * W + tw);

      edge[s].insert(t);
      edge[t].insert(s);
    }
  }

  // dfs
  int from = uf.find(Ch * W + Cw);
  int to = uf.find(Dh * W + Dw);

  queue<pair<int, int>> que;
  que.emplace(from, 0);
  set<int> visited;
  while (que.size() > 0) {
    int now, depth;
    tie(now, depth) = que.front();
    que.pop();

    if (visited.count(now) > 0)
      continue;
    visited.insert(now);

    if (now == to) {
      cout << depth << endl;
      return 0;
    }

    for (auto nxt : edge[now])
      que.emplace(nxt, depth + 1);
  }

  cout << -1 << endl;
  return 0;
}


Fixed submission:
#include <bits/stdc++.h>
#define rep(i, n, m) for (int i = (n); i < (m); i++)
#define rrep(i, n, m) for (int i = (n)-1; i >= (m); i--)
#define pvec(vec)                                                              \
  {                                                                            \
    for (auto v : vec)                                                         \
      cout << v << ' ';                                                        \
    cout << endl;                                                              \
  }
#define pivec(vec)                                                             \
  {                                                                            \
    rep(i, 0, vec.size()) cout << i << ':' << vec[i] << ' ';                   \
    cout << endl;                                                              \
  }

using namespace std;
using ll = long long;

int H, W;

struct UnionFind {
  int n;
  vector<int> parent;
  vector<int> rank;
  UnionFind(int _n) : n(_n) {
    parent.assign(n, -1);
    rank.assign(n, 1);
  }

  int find(int i) {
    if (parent[i] == -1)
      return i;
    else
      return parent[i] = find(parent[i]);
  }

  void unite(int i, int j) {
    i = find(i);
    j = find(j);

    if (i == j)
      return;

    if (rank[i] == rank[j]) {
      parent[j] = i;
      ++rank[i];
    } else {
      if (rank[i] < rank[j])
        swap(i, j);
      parent[j] = i;
    }
  }

  bool is_same(int i, int j) { return find(i) == find(j); }
};

void connect(int th, int tw, int sh, int sw, UnionFind &uf,
             const vector<string> &grid) {
  if (sh < 0 or sh >= H)
    return;
  if (sw < 0 or sw >= W)
    return;
  if (grid[th][tw] == '#')
    return;
  if (grid[sh][sw] == '#')
    return;
  uf.unite(W * th + tw, W * sh + sw);
}

int main() {
  cin >> H >> W;
  int Ch, Cw, Dh, Dw;
  cin >> Ch >> Cw;
  cin >> Dh >> Dw;

  --Ch, --Cw;
  --Dh, --Dw;

  vector<string> grid(H);
  rep(i, 0, H) cin >> grid[i];

  UnionFind uf(H * W);

  rep(h, 0, H) rep(w, 0, W) {
    connect(h, w, h - 1, w, uf, grid);
    connect(h, w, h, w - 1, uf, grid);
    connect(h, w, h + 1, w, uf, grid);
    connect(h, w, h, w + 1, uf, grid);
  }

  // make graph
  vector<set<int>> edge(H * W, set<int>());
  rep(h, 0, H) rep(w, 0, W) {
    if (grid[h][w] == '#')
      continue;

    int s = uf.find(h * W + w);
    // printf("h: %d, w: %d, s: %d\n", h, w, s);

    rep(dh, -2, 3) rep(dw, -2, 3) {
      int th = h + dh;
      int tw = w + dw;

      if (th < 0 or th >= H)
        continue;
      if (tw < 0 or tw >= W)
        continue;
      if (grid[th][tw] == '#')
        continue;

      int t = uf.find(th * W + tw);

      edge[s].insert(t);
      edge[t].insert(s);
    }
  }

  // dfs
  int from = uf.find(Ch * W + Cw);
  int to = uf.find(Dh * W + Dw);

  queue<pair<int, int>> que;
  que.emplace(from, 0);
  set<int> visited;
  while (que.size() > 0) {
    int now, depth;
    tie(now, depth) = que.front();
    que.pop();

    if (visited.count(now) > 0)
      continue;
    visited.insert(now);

    if (now == to) {
      cout << depth << endl;
      return 0;
    }

    for (auto nxt : edge[now])
      que.emplace(nxt, depth + 1);
  }

  cout << -1 << endl;
  return 0;
}