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


#include <algorithm>
#include <chrono>
#include <cmath>
#include <deque>
#include <fstream>
#include <functional>
#include <iostream>
#include <iterator>
#include <limits>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#define forr(i, start, count) for (int i = (start); i < (start) + (count); ++i)
#define set_map_includes(set, elt) (set.find((elt)) != set.end())
#define readint(i)                                                             \\
  int i;                                                                       \\
  cin >> i
#define readll(i)                                                              \\
  ll i;                                                                        \\
  cin >> i
#define readdouble(i)                                                          \\
  double i;                                                                    \\
  cin >> i
#define readstring(s)                                                          \\
  string s;                                                                    \\
  cin >> s

typedef long long ll;

using namespace std;

template <class T> class depth_first_search_iterator {
public:
  stack<pair<T, T>> todo;
  function<bool(T)> notvisited;
  function<void(T)> mark_visited;
  function<set<T>(T)> neighbors;

  depth_first_search_iterator() {}

  depth_first_search_iterator(T start, function<bool(T)> notv,
                              function<void(T)> mark_v,
                              function<set<T>(T)> neigh)
      : notvisited(notv), mark_visited(mark_v), neighbors(neigh), end_(false),
        current(start), prev(start) {
    todo.push(make_pair(start, start));
    operator++();
  }

  void operator++() {
    end_ = true;
    while (!todo.empty()) {
      current = todo.top().first;
      prev = todo.top().second;
      todo.pop();
      if (notvisited(current)) {
        mark_visited(current);
        for (const T x : neighbors(current)) {
          todo.push(make_pair(x, current));
        }
        end_ = false;
        break;
      }
    }
  }

  T operator*() { return current; }

  T previous() { return prev; }

  bool end() { return end_; }

private:
  T current; // contains current node
  T prev;    // contains previous node
  bool end_;
};

template <class T> class breadth_first_search_iterator {
public:
  queue<pair<T, T>> todo;
  function<bool(T)> notvisited;
  function<void(T)> mark_visited;
  function<set<T>(T)> neighbors;

  breadth_first_search_iterator() {}

  breadth_first_search_iterator(T start, function<bool(T)> notv,
                                function<void(T)> mark_v,
                                function<set<T>(T)> neigh)
      : notvisited(notv), mark_visited(mark_v), neighbors(neigh), end_(false),
        current(start), prev(start) {
    todo.push(make_pair(start, start));
    operator++();
  }

  void operator++() {
    end_ = true;
    while (!todo.empty()) {
      current = todo.front().first;
      prev = todo.front().second;
      todo.pop();
      if (notvisited(current)) {
        mark_visited(current);
        for (const T x : neighbors(current)) {
          todo.push(make_pair(x, current));
        }
        end_ = false;
        break;
      }
    }
  }

  T operator*() { return current; }

  T previous() { return prev; }

  bool end() { return end_; }

private:
  T current; // current node
  T prev;    // previous node
  bool end_;
};

template <class T> class Graph {
  // allows only single connection between two vertices
public:
  vector<T> vertices;
  vector<set<int>> neighbors;
  depth_first_search_iterator<int> dfs_iterator;
  breadth_first_search_iterator<int> bfs_iterator;
  vector<bool> visited;

  Graph() {}

  Graph(int n, T default_val = 0) {
    for (int i = 0; i < n; ++i) {
      AddVertex(default_val);
    }
  }

  void AddVertex(T val) {
    vertices.push_back(val);
    neighbors.push_back(set<int>());
  }

  bool EdgeExists(int i, int j) {
    return (neighbors[i].find(j) != neighbors[i].end());
  }

  void AddEdge(int i, int j) {
    if (i == j) {
      return;
    }
    if (!EdgeExists(i, j)) {
      neighbors[i].insert(j);
      if (i != j) {
        neighbors[j].insert(i);
      }
    }
  }

  T &operator[](int i) { return vertices[i]; }

  void RemoveEdge(int i, int j) {
    if (EdgeExists(i, j)) {
      neighbors[i].erase(find(neighbors[i].begin(), neighbors[i].end(), j));
      neighbors[j].erase(find(neighbors[j].begin(), neighbors[j].end(), i));
    }
  }

  int vertices_count() { return vertices.size(); }

  void dfs_init(int start) {
    visited = vector<bool>(vertices.size(), false);
    dfs_iterator = depth_first_search_iterator<int>(
        start, [this](int x) { return !visited[x]; },
        [this](int x) { visited[x] = true; },
        [this](int x) { return neighbors[x]; });
  }

  void bfs_init(int start) {
    visited = vector<bool>(vertices.size(), false);
    bfs_iterator = breadth_first_search_iterator<int>(
        start, [this](int x) { return !visited[x]; },
        [this](int x) { visited[x] = true; },
        [this](int x) { return neighbors[x]; });
  }

  void print_() {
    forr(i, 0, vertices.size()) {
      for (auto x : neighbors[i]) {
        if (i <= x) {
          cout << i << "-" << x << endl;
        }
      }
    }
  }
};

class UnionFind {
public:
  vector<int> parent;
  vector<int> size;
  //      size[i] = number of nodes in tree rooted at i
  // Note: not necessarily correct if i is not a root node
  set<int> roots;

  UnionFind(int n) : parent(n), size(n) {
    forr(i, 0, n) { roots.insert(i); }
    forr(i, 0, n) {
      parent[i] = i;
      size[i] = 1;
    }
  }

  int Find(int p) {
    int root = p;
    while (root != parent[root]) {
      root = parent[root];
    }
    while (p != root) {
      int newp = parent[p];
      parent[p] = root;
      p = newp;
    }
    return root;
  }

  void Union(int p, int q) {
    int rootP = Find(p);
    int rootQ = Find(q);
    if (rootP == rootQ)
      return;

    // make smaller root point to larger one
    if (size[rootP] < size[rootQ]) {
      parent[rootP] = rootQ;
      size[rootQ] += size[rootP];
      roots.erase(rootP);
    } else {
      parent[rootQ] = rootP;
      size[rootP] += size[rootQ];
      roots.erase(rootQ);
    }
  }
};

template <class T>
pair<vector<T>, vector<int>> DijkstraUndirected(int N_vertices,
                                                map<pair<int, int>, T> &edges,
                                                int s, T infinity) {
  // input edges with weight of type T, return two arrays: first contains
  // shortest distance from s, second (prev) contains info on constructing path:
  // start at vertex t, go to prev[t], then prev[prev[t]], until s, you get
  // (shortest) path from t to s infinity should be higher than all distances,
  // and too high to prevent weird wraparound  effects in addition
  // dist[u]+edges[]... below

  vector<T> dist(N_vertices, infinity);
  dist[s] = 0;
  vector<int> prev(N_vertices);
  set<pair<T, int>> Q;
  for (int i = 0; i < N_vertices; ++i) {
    Q.insert(make_pair(dist[i], i));
  }
  Graph<int> g(N_vertices);
  for (auto x : edges) {
    g.AddEdge(x.first.first, x.first.second);
  }

  while (!Q.empty()) {
    int u = Q.begin()->second;
    Q.erase(Q.begin());

    for (int v : g.neighbors[u]) {
      T one_way = 0, other_way = 0;
      if (edges.find(make_pair(u, v)) != edges.end()) {
        one_way = edges[make_pair(u, v)];
      }
      if (edges.find(make_pair(v, u)) != edges.end()) {
        other_way = edges[make_pair(v, u)];
      }
      T alt = dist[u] + one_way +
              other_way; // since each edge is present in only one of those
                         // edges[u,v] & edges[v,u] if you need modification for
                         // directed graph, only first edges should be used
                         // CAREFUL!!!! edges should contain each edge only
                         // once!!! not twice for both directions
      if (alt < dist[v]) {
        prev[v] = u;
        Q.erase(make_pair(dist[v], v));
        dist[v] = alt;
        Q.insert(make_pair(dist[v], v));
      }
    }
  }

  return make_pair(dist, prev);
};

template <class T>
pair<vector<int>, vector<int>> DijkstraUndirectedGraph(
    Graph<T> &g, int s,
    int infinity =
        -1) { // does dijsktra undirected on a graph, returns the same as above
  map<pair<int, int>, int> edges;
  int count = 0;
  for (int i = 0; i < g.vertices.size(); ++i) {
    for (auto w : g.neighbors[i]) {
      if ((edges.find(make_pair(i, w)) == edges.end()) &&
          (edges.find(make_pair(w, i)) == edges.end())) {
        edges[make_pair(i, w)] = 1;
      }
      ++count;
    }
  }
  if (infinity == -1) {
    return DijkstraUndirected<int>(g.vertices.size(), edges, s, count + 1);
  } else {
    return DijkstraUndirected<int>(g.vertices.size(), edges, s, infinity);
  }
};

ll modd = 1000 * 1000 * 1000 + 7;
int h, w;

int ind(int hh, int ww) { return (hh * w + ww); }

int main() {

  ios_base::sync_with_stdio(false);

  cout.precision(17);
  mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
  uniform_int_distribution<int> rand_gen(
      0, modd); // rand_gen(rng) gets the rand no

  //    auto start = chrono::steady_clock::now()

  //    readint(test_cases);
  int test_cases = 1;
  forr(t, 1, test_cases) {
    readint(hh);
    readint(ww);
    h = hh;
    w = ww;
    readint(s1);
    readint(s2);
    s1--;
    s2--;
    readint(g1);
    readint(g2);
    g1--;
    g2--;
    vector<string> grid;
    forr(i, 0, h) {
      readstring(s);
      grid.push_back(s);
    }
    UnionFind uf(h * w);
    forr(i, 0, h) {
      forr(j, 0, w) {
        if ((i - 1 >= 0) && (grid[i - 1][j] == '.') && (grid[i][j] == '.')) {
          uf.Union(ind(i, j), ind(i - 1, j));
        }
        if ((j - 1 >= 0) && (grid[i][j - 1] == '.') && (grid[i][j] == '.')) {
          uf.Union(ind(i, j), ind(i, j - 1));
        }
        if ((i + 1 < h) && (grid[i + 1][j] == '.') && (grid[i][j] == '.')) {
          uf.Union(ind(i, j), ind(i + 1, j));
        }
        if ((j + 1 < w) && (grid[i][j + 1] == '.') && (grid[i][j] == '.')) {
          uf.Union(ind(i, j), ind(i, j + 1));
        }
      }
    }

    map<int, int> root_dict;
    for (int x : uf.roots) {
      int ind_ = root_dict.size();
      root_dict[x] = ind_;
    }
    Graph<int> g(uf.roots.size());
    forr(i, 0, h) {
      forr(j, 0, w) {
        if (grid[i][j] != '.') {
          continue;
        }
        for (int ii = -2; ii <= 2; ii++) {
          for (int jj = -2; jj <= 2; jj++) {
            int x1 = i + ii, y1 = j + jj;
            if ((x1 >= 0) && (y1 >= 0) && (x1 < h) && (y1 < w) &&
                (grid[x1][y1] == '.')) {
              g.AddEdge(root_dict[uf.Find(ind(i, j))],
                        root_dict[uf.Find(ind(x1, y1))]);
            }
          }
        }
      }
    }

    ll ret = -1;
    if (root_dict[uf.Find(ind(g1, g2))] == root_dict[uf.Find(ind(s1, s2))]) {
      ret = 0;
    } else {
      g.bfs_init(root_dict[uf.Find(ind(s1, s2))]);
      ++g.bfs_iterator;
      while (!g.bfs_iterator.end()) {
        g[*g.bfs_iterator] = 1 + g[g.bfs_iterator.previous()];
        if (*g.bfs_iterator == root_dict[uf.Find(ind(g1, g2))]) {
          ret = g[*g.bfs_iterator];
          break;
        }
        ++g.bfs_iterator;
      }
    }
    cout << ret << endl;

    /*        auto q = DijkstraUndirectedGraph(g,
       root_dict[uf.Find(ind(s1,s2))], modd).first; if
       (q[root_dict[uf.Find(ind(g1,g2))]]>h*w) { cout << -1 << endl; } else {
                cout << q[root_dict[uf.Find(ind(g1,g2))]] << endl;
            } */
  }

  //    auto end = chrono::steady_clock::now();
  //    cerr << chrono::duration_cast<chrono::milliseconds>(end - start).count()
  //    << endl;

  return 0;
}

Error: TLE

Fixed submission:


#include <algorithm>
#include <chrono>
#include <cmath>
#include <deque>
#include <fstream>
#include <functional>
#include <iostream>
#include <iterator>
#include <limits>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#define forr(i, start, count) for (int i = (start); i < (start) + (count); ++i)
#define set_map_includes(set, elt) (set.find((elt)) != set.end())
#define readint(i)                                                             \\
  int i;                                                                       \\
  cin >> i
#define readll(i)                                                              \\
  ll i;                                                                        \\
  cin >> i
#define readdouble(i)                                                          \\
  double i;                                                                    \\
  cin >> i
#define readstring(s)                                                          \\
  string s;                                                                    \\
  cin >> s

typedef long long ll;

using namespace std;

template <class T> class depth_first_search_iterator {
public:
  stack<pair<T, T>> todo;
  function<bool(T)> notvisited;
  function<void(T)> mark_visited;
  function<set<T>(T)> neighbors;

  depth_first_search_iterator() {}

  depth_first_search_iterator(T start, function<bool(T)> notv,
                              function<void(T)> mark_v,
                              function<set<T>(T)> neigh)
      : notvisited(notv), mark_visited(mark_v), neighbors(neigh), end_(false),
        current(start), prev(start) {
    todo.push(make_pair(start, start));
    operator++();
  }

  void operator++() {
    end_ = true;
    while (!todo.empty()) {
      current = todo.top().first;
      prev = todo.top().second;
      todo.pop();
      if (notvisited(current)) {
        mark_visited(current);
        for (const T x : neighbors(current)) {
          todo.push(make_pair(x, current));
        }
        end_ = false;
        break;
      }
    }
  }

  T operator*() { return current; }

  T previous() { return prev; }

  bool end() { return end_; }

private:
  T current; // contains current node
  T prev;    // contains previous node
  bool end_;
};

template <class T> class breadth_first_search_iterator {
public:
  queue<pair<T, T>> todo;
  function<bool(T)> notvisited;
  function<void(T)> mark_visited;
  function<set<T>(T)> neighbors;

  breadth_first_search_iterator() {}

  breadth_first_search_iterator(T start, function<bool(T)> notv,
                                function<void(T)> mark_v,
                                function<set<T>(T)> neigh)
      : notvisited(notv), mark_visited(mark_v), neighbors(neigh), end_(false),
        current(start), prev(start) {
    todo.push(make_pair(start, start));
    operator++();
  }

  void operator++() {
    end_ = true;
    while (!todo.empty()) {
      current = todo.front().first;
      prev = todo.front().second;
      todo.pop();
      if (notvisited(current)) {
        mark_visited(current);
        for (const T x : neighbors(current)) {
          todo.push(make_pair(x, current));
        }
        end_ = false;
        break;
      }
    }
  }

  T operator*() { return current; }

  T previous() { return prev; }

  bool end() { return end_; }

private:
  T current; // current node
  T prev;    // previous node
  bool end_;
};

template <class T> class Graph {
  // allows only single connection between two vertices
public:
  vector<T> vertices;
  vector<set<int>> neighbors;
  depth_first_search_iterator<int> dfs_iterator;
  breadth_first_search_iterator<int> bfs_iterator;
  vector<bool> visited;

  Graph() {}

  Graph(int n, T default_val = 0) {
    for (int i = 0; i < n; ++i) {
      AddVertex(default_val);
    }
  }

  void AddVertex(T val) {
    vertices.push_back(val);
    neighbors.push_back(set<int>());
  }

  bool EdgeExists(int i, int j) {
    return (neighbors[i].find(j) != neighbors[i].end());
  }

  void AddEdge(int i, int j) {
    if (!EdgeExists(i, j)) {
      neighbors[i].insert(j);
      if (i != j) {
        neighbors[j].insert(i);
      }
    }
  }

  T &operator[](int i) { return vertices[i]; }

  void RemoveEdge(int i, int j) {
    if (EdgeExists(i, j)) {
      neighbors[i].erase(find(neighbors[i].begin(), neighbors[i].end(), j));
      neighbors[j].erase(find(neighbors[j].begin(), neighbors[j].end(), i));
    }
  }

  int vertices_count() { return vertices.size(); }

  void dfs_init(int start) {
    visited = vector<bool>(vertices.size(), false);
    dfs_iterator = depth_first_search_iterator<int>(
        start, [this](int x) { return !visited[x]; },
        [this](int x) { visited[x] = true; },
        [this](int x) { return neighbors[x]; });
  }

  void bfs_init(int start) {
    visited = vector<bool>(vertices.size(), false);
    bfs_iterator = breadth_first_search_iterator<int>(
        start, [this](int x) { return !visited[x]; },
        [this](int x) { visited[x] = true; },
        [this](int x) { return neighbors[x]; });
  }

  void print_() {
    forr(i, 0, vertices.size()) {
      for (auto x : neighbors[i]) {
        if (i <= x) {
          cout << i << "-" << x << endl;
        }
      }
    }
  }
};

class UnionFind {
public:
  vector<int> parent;
  vector<int> size;
  //      size[i] = number of nodes in tree rooted at i
  // Note: not necessarily correct if i is not a root node
  set<int> roots;

  UnionFind(int n) : parent(n), size(n) {
    forr(i, 0, n) { roots.insert(i); }
    forr(i, 0, n) {
      parent[i] = i;
      size[i] = 1;
    }
  }

  int Find(int p) {
    int root = p;
    while (root != parent[root]) {
      root = parent[root];
    }
    while (p != root) {
      int newp = parent[p];
      parent[p] = root;
      p = newp;
    }
    return root;
  }

  void Union(int p, int q) {
    int rootP = Find(p);
    int rootQ = Find(q);
    if (rootP == rootQ)
      return;

    // make smaller root point to larger one
    if (size[rootP] < size[rootQ]) {
      parent[rootP] = rootQ;
      size[rootQ] += size[rootP];
      roots.erase(rootP);
    } else {
      parent[rootQ] = rootP;
      size[rootP] += size[rootQ];
      roots.erase(rootQ);
    }
  }
};

template <class T>
pair<vector<T>, vector<int>> DijkstraUndirected(int N_vertices,
                                                map<pair<int, int>, T> &edges,
                                                int s, T infinity) {
  // input edges with weight of type T, return two arrays: first contains
  // shortest distance from s, second (prev) contains info on constructing path:
  // start at vertex t, go to prev[t], then prev[prev[t]], until s, you get
  // (shortest) path from t to s infinity should be higher than all distances,
  // and too high to prevent weird wraparound  effects in addition
  // dist[u]+edges[]... below

  vector<T> dist(N_vertices, infinity);
  dist[s] = 0;
  vector<int> prev(N_vertices);
  set<pair<T, int>> Q;
  for (int i = 0; i < N_vertices; ++i) {
    Q.insert(make_pair(dist[i], i));
  }
  Graph<int> g(N_vertices);
  for (auto x : edges) {
    g.AddEdge(x.first.first, x.first.second);
  }

  while (!Q.empty()) {
    int u = Q.begin()->second;
    Q.erase(Q.begin());

    for (int v : g.neighbors[u]) {
      T one_way = 0, other_way = 0;
      if (edges.find(make_pair(u, v)) != edges.end()) {
        one_way = edges[make_pair(u, v)];
      }
      if (edges.find(make_pair(v, u)) != edges.end()) {
        other_way = edges[make_pair(v, u)];
      }
      T alt = dist[u] + one_way +
              other_way; // since each edge is present in only one of those
                         // edges[u,v] & edges[v,u] if you need modification for
                         // directed graph, only first edges should be used
                         // CAREFUL!!!! edges should contain each edge only
                         // once!!! not twice for both directions
      if (alt < dist[v]) {
        prev[v] = u;
        Q.erase(make_pair(dist[v], v));
        dist[v] = alt;
        Q.insert(make_pair(dist[v], v));
      }
    }
  }

  return make_pair(dist, prev);
};

template <class T>
pair<vector<int>, vector<int>> DijkstraUndirectedGraph(
    Graph<T> &g, int s,
    int infinity =
        -1) { // does dijsktra undirected on a graph, returns the same as above
  map<pair<int, int>, int> edges;
  int count = 0;
  for (int i = 0; i < g.vertices.size(); ++i) {
    for (auto w : g.neighbors[i]) {
      if ((edges.find(make_pair(i, w)) == edges.end()) &&
          (edges.find(make_pair(w, i)) == edges.end())) {
        edges[make_pair(i, w)] = 1;
      }
      ++count;
    }
  }
  if (infinity == -1) {
    return DijkstraUndirected<int>(g.vertices.size(), edges, s, count + 1);
  } else {
    return DijkstraUndirected<int>(g.vertices.size(), edges, s, infinity);
  }
};

ll modd = 1000 * 1000 * 1000 + 7;
int h, w;

int ind(int hh, int ww) { return (hh * w + ww); }

int main() {

  ios_base::sync_with_stdio(false);

  cout.precision(17);
  mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
  uniform_int_distribution<int> rand_gen(
      0, modd); // rand_gen(rng) gets the rand no

  //    auto start = chrono::steady_clock::now()

  //    readint(test_cases);
  int test_cases = 1;
  forr(t, 1, test_cases) {
    readint(hh);
    readint(ww);
    h = hh;
    w = ww;
    readint(s1);
    readint(s2);
    s1--;
    s2--;
    readint(g1);
    readint(g2);
    g1--;
    g2--;
    vector<string> grid;
    forr(i, 0, h) {
      readstring(s);
      grid.push_back(s);
    }
    UnionFind uf(h * w);
    forr(i, 0, h) {
      forr(j, 0, w) {
        if ((i - 1 >= 0) && (grid[i - 1][j] == '.') && (grid[i][j] == '.')) {
          uf.Union(ind(i, j), ind(i - 1, j));
        }
        if ((j - 1 >= 0) && (grid[i][j - 1] == '.') && (grid[i][j] == '.')) {
          uf.Union(ind(i, j), ind(i, j - 1));
        }
        if ((i + 1 < h) && (grid[i + 1][j] == '.') && (grid[i][j] == '.')) {
          uf.Union(ind(i, j), ind(i + 1, j));
        }
        if ((j + 1 < w) && (grid[i][j + 1] == '.') && (grid[i][j] == '.')) {
          uf.Union(ind(i, j), ind(i, j + 1));
        }
      }
    }

    map<int, int> root_dict;
    for (int x : uf.roots) {
      int ind_ = root_dict.size();
      root_dict[x] = ind_;
    }
    Graph<int> g(uf.roots.size());
    forr(i, 0, h) {
      forr(j, 0, w) {
        if (grid[i][j] != '.') {
          continue;
        }
        for (int ii = -2; ii <= 2; ii++) {
          for (int jj = -2; jj <= 2; jj++) {
            int x1 = i + ii, y1 = j + jj;
            if ((x1 >= 0) && (y1 >= 0) && (x1 < h) && (y1 < w) &&
                (grid[x1][y1] == '.')) {
              g.AddEdge(root_dict[uf.Find(ind(i, j))],
                        root_dict[uf.Find(ind(x1, y1))]);
            }
          }
        }
      }
    }

    auto q =
        DijkstraUndirectedGraph(g, root_dict[uf.Find(ind(s1, s2))], modd).first;
    if (q[root_dict[uf.Find(ind(g1, g2))]] > h * w) {
      cout << -1 << endl;
    } else {
      cout << q[root_dict[uf.Find(ind(g1, g2))]] << endl;
    }
  }

  //    auto end = chrono::steady_clock::now();
  //    cerr << chrono::duration_cast<chrono::milliseconds>(end - start).count()
  //    << endl;

  return 0;
}