#include <bits/stdc++.h>
using namespace std;
#define FOR(i,k,n) for(int i = (k); i < (int)(n); i++)
#define REP(i,n) FOR(i,0,n)
#define ALL(a) a.begin(), a.end()
#define MS(m,v) memset(m,v,sizeof(m))
#define D10 fixed<<setprecision(10)
typedef long long ll;
typedef long double ld;
typedef vector<int> vi;
typedef vector<string> vs;
typedef pair<int, int> pii;
const int MOD = 1000000007;
const int INF = MOD + 1;
const ld EPS = 1e-12;
template<class T> T &chmin(T &a, const T &b) { return a = min(a, b); }
template<class T> T &chmax(T &a, const T &b) { return a = max(a, b); }

/*--------------------template--------------------*/
struct union_find
{
	vector<int> par;
	union_find(int n) 
	{
		REP(i, n) par.push_back(i);
	}
	int find(int x) { return par[x] == x ? x : par[x] = find(par[x]); }
	void unite(int x, int y)
	{
		x = find(x); y = find(y);
		if (x == y) return;
		par[y] = x;
		if (find(x) != find(y)) par[find(y)] = x;
	}
	int count()
	{
		int cnt = 0;
		REP(i, par.size()) if (par[i] == i) cnt++;
		return cnt;
	}
	bool same(int x, int y)
	{
		return find(x) == find(y);
	}
};

int main()
{
	int n, w, h;
	cin >> n >> w >> h;
	vector<vi> x(h), y(w);
	union_find uf(n);
	REP(i, n)
	{
		int a, b; cin >> b >> a;
		a--; b--;
		x[a].push_back(i), y[b].push_back(i);
	}
	REP(i, h)REP(j, x[i].size() - 1) uf.unite(x[i][j], x[i][j + 1]);
	REP(i, w)REP(j, y[i].size() - 1) uf.unite(y[i][j], y[i][j + 1]);
	ll cnt = uf.count();
	ll ans = n - cnt;
	if (cnt > 1)
	{
		ans += cnt;
		ans += cnt - 1;
		if (x[0].size() || x[h - 1].size() || y[0].size() || y[w - 1].size()) ans--;
	}
	cout << ans << endl;
	return 0;
}