Problem p03682 (C++)

Buggy submission (status: Time Limit Exceeded):
#include <algorithm>
#include <cassert>
#include <functional>
#include <iostream>
#include <unordered_map>
#include <vector>
using namespace std;

class Point {
public:
  int x, y;
  Point() {}
  Point(int x, int y) : x(x), y(y) {}

  bool operator==(const Point &other) const {
    return this->x == other.x && this->y == other.y;
  }

  static bool cmp_x(Point p, Point q) { return p.x < q.x; }

  static bool cmp_y(Point p, Point q) { return p.y < q.y; }
};

class UnionFind {
  struct Hash {
    size_t operator()(const Point &key) const {
      return hash<int>()(key.x * key.y + key.y);
    }
  };

  unordered_map<Point, Point, Hash> parent;
  unordered_map<Point, int, Hash> rank;

public:
  Point root(Point x) {
    if (parent.find(x) == parent.end()) {
      parent[x] = x;
      rank[x] = 1;
      return x;
    }
    return parent[x] == x ? x : parent[x] = root(parent[x]);
  }

  bool is_same(Point x, Point y) { return root(x) == root(y); }

  void unite(Point x, Point y) {
    x = root(x);
    y = root(y);
    if (x == y)
      return;
    if (rank[x] < rank[y])
      swap(x, y);
    if (rank[x] == rank[y])
      rank[x]++;
    parent[y] = x;
  }
};

class UndirectedGraph {
  class Edge {
  public:
    pair<Point, Point> vertex;
    int cost;

    Edge(Point i, Point j, int cost) : vertex(make_pair(i, j)), cost(cost) {}

    bool operator<(const Edge &other) const { return this->cost < other.cost; }
  };

  vector<Edge> edges;

public:
  void connect(Point i, Point j, int cost) {
    edges.push_back(Edge(i, j, cost));
  }

  int kluskal() {
    sort(edges.begin(), edges.end());
    UnionFind uf;
    int res = 0;
    for (Edge e : edges) {
      pair<Point, Point> p = e.vertex;
      Point u = p.first;
      Point v = p.second;
      if (!uf.is_same(u, v)) {
        uf.unite(u, v);
        res += e.cost;
      }
    }
    return res;
  }
};

int main() {
  UndirectedGraph g;
  int n;
  cin >> n;
  vector<Point> ps(n), qs(n);
  for (int i = 0; i < n; ++i) {
    int x, y;
    cin >> x >> y;
    ps[i] = qs[i] = Point(x, y);
  }
  sort(ps.begin(), ps.end(), Point::cmp_x);
  sort(qs.begin(), qs.end(), Point::cmp_y);
  for (int i = 0; i < n - 1; ++i) {
    g.connect(ps[i], ps[i + 1], ps[i + 1].x - ps[i].x);
    g.connect(qs[i], qs[i + 1], qs[i + 1].y - qs[i].y);
  }
  cout << g.kluskal() << endl;
}

Fixed submission:
#include <algorithm>
#include <cassert>
#include <functional>
#include <iostream>
#include <unordered_map>
#include <vector>
using namespace std;

class Point {
public:
  int x, y;
  Point() {}
  Point(int x, int y) : x(x), y(y) {}

  bool operator==(const Point &other) const {
    return this->x == other.x && this->y == other.y;
  }

  static bool cmp_x(Point p, Point q) { return p.x < q.x; }

  static bool cmp_y(Point p, Point q) { return p.y < q.y; }
};

class UnionFind {
  struct Hash {
    size_t operator()(const Point &key) const {
      return hash<int>()((key.x + 1) * (key.y + 1));
    }
  };

  unordered_map<Point, Point, Hash> parent;
  unordered_map<Point, int, Hash> rank;

public:
  Point root(Point x) {
    if (parent.find(x) == parent.end()) {
      parent[x] = x;
      rank[x] = 1;
      return x;
    }
    return parent[x] == x ? x : parent[x] = root(parent[x]);
  }

  bool is_same(Point x, Point y) { return root(x) == root(y); }

  void unite(Point x, Point y) {
    x = root(x);
    y = root(y);
    if (x == y)
      return;
    if (rank[x] < rank[y])
      swap(x, y);
    if (rank[x] == rank[y])
      rank[x]++;
    parent[y] = x;
  }
};

class UndirectedGraph {
  class Edge {
  public:
    pair<Point, Point> vertex;
    int cost;

    Edge(Point i, Point j, int cost) : vertex(make_pair(i, j)), cost(cost) {}

    bool operator<(const Edge &other) const { return this->cost < other.cost; }
  };

  vector<Edge> edges;

public:
  void connect(Point i, Point j, int cost) {
    edges.push_back(Edge(i, j, cost));
  }

  int kluskal() {
    sort(edges.begin(), edges.end());
    UnionFind uf;
    int res = 0;
    for (Edge e : edges) {
      pair<Point, Point> p = e.vertex;
      Point u = p.first;
      Point v = p.second;
      if (!uf.is_same(u, v)) {
        uf.unite(u, v);
        res += e.cost;
      }
    }
    return res;
  }
};

int main() {
  UndirectedGraph g;
  int n;
  cin >> n;
  vector<Point> ps(n), qs(n);
  for (int i = 0; i < n; ++i) {
    int x, y;
    cin >> x >> y;
    ps[i] = qs[i] = Point(x, y);
  }
  sort(ps.begin(), ps.end(), Point::cmp_x);
  sort(qs.begin(), qs.end(), Point::cmp_y);
  for (int i = 0; i < n - 1; ++i) {
    g.connect(ps[i], ps[i + 1], ps[i + 1].x - ps[i].x);
    g.connect(qs[i], qs[i + 1], qs[i + 1].y - qs[i].y);
  }
  cout << g.kluskal() << endl;
}