Problem p02579 (C++) — buggy submission, verdict: Time Limit Exceeded

#include <bits/stdc++.h>

using namespace std;
using ll = long long;

int main() {
  cin.tie(nullptr);
  ios::sync_with_stdio(false);

  int h, w;
  cin >> h >> w;
  int ch, cw;
  int dh, dw;
  cin >> ch >> cw;
  cin >> dh >> dw;
  ch--;
  cw--;
  dh--;
  dw--;
  vector<vector<char>> s(h, vector<char>(w));
  for (int i = 0; i < h; i++) {
    for (int j = 0; j < w; j++) {
      cin >> s[i][j];
    }
  }

  auto check = [&](int x, int y) {
    if (x < 0 || x >= w || y < 0 || y >= h)
      return false;
    if (s[y][x] == '#')
      return false;
    return true;
  };

  queue<tuple<int, int>> q;
  int d = 0;
  q.push({cw, ch});
  vector<vector<bool>> visit(h, vector<bool>(w, false));
  while (true) {
    vector<pair<int, int>> v;
    while (!q.empty()) {
      auto [x, y] = q.front();
      q.pop();
      if (visit[y][x])
        continue;
      visit[y][x] = true;
      v.push_back({x, y});
      if (x == dw && y == dh) {
        cout << d << endl;
        return 0;
      }

      if (check(x + 1, y))
        q.push({x + 1, y});
      if (check(x - 1, y))
        q.push({x - 1, y});
      if (check(x, y + 1))
        q.push({x, y + 1});
      if (check(x, y - 1))
        q.push({x, y - 1});
    }
    for (auto [x, y] : v) {
      for (int dy = -2; dy <= 2; dy++) {
        for (int dx = -2; dx <= 2; dx++) {
          if (dx == 0 && dy == 0)
            continue;
          if (dx == 1 && dy == 0)
            continue;
          if (dx == -1 && dy == 0)
            continue;
          if (dx == 0 && dy == 1)
            continue;
          if (dx == 0 && dy == -1)
            continue;
          int nx = x + dx;
          int ny = y + dy;
          if (!check(nx, ny))
            continue;
          if (visit[ny][nx])
            continue;
          q.push({nx, ny});
        }
      }
    }
    d++;
    if (q.empty())
      break;
  }

  cout << -1 << endl;

  return 0;
}


Error: TLE

Fixed submission:

#include <bits/stdc++.h>

using namespace std;
using ll = long long;

class UnionFind {
public:
  UnionFind(int n) : tree(vector<ll>(n, -1)) {}

  // 木の頂点を探す
  int find(int x) {
    if (tree[x] < 0)
      return x;
    return tree[x] = find(tree[x]);
  }

  // 長さを返す
  ll length(int x) {
    if (tree[x] < 0)
      return abs(tree[x]);
    return length(tree[x]);
  }

  // 同じグループか
  bool same(int x, int y) { return find(x) == find(y); }

  // 点xを含む木と点yを含む木の融合
  // 既に同じ木だったらfalseを返す
  bool unite(int x, int y) {
    int r1 = find(x);
    int r2 = find(y);
    if (r1 == r2)
      return false;
    // 大きい方に小さい方をくっつけたほうがコストが低い
    if (abs(r1) < abs(r2))
      swap(r1, r2);
    tree[r1] += tree[r2];
    tree[r2] = r1;
    return true;
  }

private:
  vector<ll> tree;
};

int main() {
  cin.tie(nullptr);
  ios::sync_with_stdio(false);

  int h, w;
  cin >> h >> w;
  int ch, cw;
  int dh, dw;
  cin >> ch >> cw;
  cin >> dh >> dw;
  ch--;
  cw--;
  dh--;
  dw--;
  vector<vector<char>> s(h, vector<char>(w));
  for (int i = 0; i < h; i++) {
    for (int j = 0; j < w; j++) {
      cin >> s[i][j];
    }
  }

  auto id = [&](int x, int y) { return y * 1000 + x; };

  auto check = [&](int x, int y) {
    if (x < 0 || x >= w || y < 0 || y >= h)
      return false;
    if (s[y][x] == '#')
      return false;
    return true;
  };

  UnionFind uf(id(w - 1, h - 1) + 1);
  auto root = [&](int x, int y) { return uf.find(id(x, y)); };

  for (int y = 0; y < h; y++) {
    for (int x = 0; x < w; x++) {
      if (!check(x, y))
        continue;
      if (check(x + 1, y))
        uf.unite(id(x, y), id(x + 1, y));
      if (check(x - 1, y))
        uf.unite(id(x, y), id(x - 1, y));
      if (check(x, y + 1))
        uf.unite(id(x, y), id(x, y + 1));
      if (check(x, y - 1))
        uf.unite(id(x, y), id(x, y - 1));
    }
  }

  map<int, vector<int>> m;

  for (int y = 0; y < h; y++) {
    for (int x = 0; x < w; x++) {
      for (int dy = -2; dy <= 2; dy++) {
        for (int dx = -2; dx <= 2; dx++) {
          if (abs(dx) <= 1 && abs(dy) <= 1)
            continue;
          if (!check(x, y))
            continue;
          int nx = x + dx;
          int ny = y + dy;
          if (!check(nx, ny))
            continue;
          if (uf.same(id(x, y), id(nx, ny)))
            continue;
          m[root(x, y)].push_back(root(nx, ny));
          m[root(nx, ny)].push_back(root(x, y));
        }
      }
    }
  }

  map<int, int> ans;

  function<void(int, int)> dfs = [&](int cur, int c) {
    if (ans.count(cur) != 0 && ans[cur] <= c)
      return;
    ans[cur] = c;
    for (auto next : m[cur]) {
      dfs(next, c + 1);
    }
  };

  int start = root(cw, ch);
  int goal = root(dw, dh);
  dfs(start, 0);

  cout << (ans.count(goal) == 0 ? -1 : ans[goal]) << endl;

  return 0;
}