Problem:
Problem D: King Slime

There is a grid of size W × H surrounded by walls. Some cells in the grid are occupied by slimes. The slimes want to unite with each other and become a "King Slime".

In each move, a slime can move to east, west, south and north direction until it enters a cell occupied by another slime or hit the surrounding wall. If two slimes come together, they unite and become a new slime.

Your task is write a program which calculates the minimum number of moves that all the slimes unite and become a King Slime. Suppose slimes move one by one and they never move simultaneously.

Input

The first line contains three integers N (2 ≤ N ≤ 40,000), W and H (1 ≤ W, H ≤ 100,000), which denote the
number of slimes, the width and the height of the grid respectively.

The following N lines describe the initial coordinates of the slimes. The i-th line contains two integers xi (1 ≤ xi ≤ W) and yi (1 ≤ yi ≤ H), which indicate the coordinates of the i-th slime . All the coordinates are 1-based.

You may assume that each cell is occupied by at most one slime initially.

Output

Output the minimum number of moves that all the slimes unite and become a King Slime.

Sample Input 1

4 3 3
1 1
1 3
3 1
3 3

Output for the Sample Input 1

3

Sample Input 2

2 3 3
2 2
3 3

Output for the Sample Input 2

2

Sample Input 3

2 4 4
2 2
3 3

Output for the Sample Input 3

3

Sample Input 4

2 4 4
2 2
2 3

Output for the Sample Input 4

1

Solution in C++14 (judge verdict: Wrong Answer)

#include <bits/stdc++.h>
#define FOR(i,k,n) for(int i=(k);i<(int)(n);++i)
#define REP(i,n) FOR(i,0,n)
#define ALL(x) begin(x),end(x)

using namespace std;
typedef int Weight;
Weight INF = 1000000000;

struct UnionFind {
  vector<int> parent;
  UnionFind (int n) : parent(n, -1) {}
  int root(int x) { return parent[x] < 0 ? x : parent[x] = root(parent[x]); }
  bool merge(int x, int y) {
    x = root(x); y = root(y);
    if (x == y) return false;
    if (parent[y] < parent[x]) swap(x, y);
    if (parent[x] == parent[y]) --parent[x];
    parent[y] = x;
    return true;
  }
};
typedef int Weight;
struct Edge{
  int src, dest; Weight weight;
  bool operator < (const Edge &rhs) const {return weight > rhs.weight;}
};

typedef vector<Edge> Edges;

// Kruskal
// N, operator <
Edges kruskal(int V, Edges &es) {
  sort(es.rbegin(), es.rend());
  UnionFind uf(V);
  Edges res;
  REP(i, es.size()) {
    Edge e = es[i];
    if(uf.root(e.src) != uf.root(e.dest)) {
      uf.merge(e.src, e.dest);
      res.push_back(e);
    }
  }
  return res;
}

int check(const Edges& ve, const vector<int>& id, int len, const vector<bool> &cond, int n) {
  auto tmp = ve;
  int cnt = 0;
  FOR(i,1,len+1) {
    if (id[i] >= 0) {
      tmp.push_back((Edge){id[i], n+cnt, !cond[i]});
      if(cnt) tmp.push_back((Edge){n+cnt, n, 1});
      ++cnt;
    }
  }
  auto rve = kruskal(n+cnt,tmp);
  int sum = 0;
  for (auto e:rve) sum += e.weight;
  if ((int)rve.size() == n+cnt-1) return sum;
  else return INF;
}

int main() {
  int n,w,h;
  cin>>n>>w>>h;
  vector<int> ix(w+1,-1);
  vector<bool> ixx(w+1);
  vector<bool> ixn(w+1);
  vector<int> iy(h+1,-1);
  vector<bool> iyx(h+1);
  vector<bool> iyn(h+1);
  Edges ve;
  REP(i,n) {
    int x,y;
    cin>>x>>y;
    if (ix[x] == -1) {
      ix[x] = i;
      ixx[x] = y == h;
      ixn[x] = y == 1;
    } else {
      ixx[x] = ixx[x] || y == h;
      ixn[x] = ixn[x] || y == 1;
      ve.push_back((Edge){i, ix[x], 1});
    }
    if (iy[y] == -1) {
      iy[y] = i;
      iyx[y] = x == w;
      iyn[y] = x == 1;
    } else {
      iyx[y] = iyx[y] || x == w;
      iyn[y] = iyn[y] || x == 1;
      ve.push_back((Edge){i, iy[y], 1});
    }
  }
  int res = INF;
  auto rve = kruskal(n,ve);
  int sum = 0;
  for (auto e:rve) sum += e.weight;
  if ((int)rve.size() == n-1) res = min(res, sum);
  res = min(res, check(ve, ix, w, ixn, n));
  res = min(res, check(ve, ix, w, ixx, n));
  res = min(res, check(ve, iy, h, iyn, n));
  res = min(res, check(ve, iy, h, iyx, n));
  cout << res << endl;
  return 0;
}