#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; static const double EPS = 1e-8; static const double PI = 4.0 * atan(1.0); static const double PI2 = 8.0 * atan(1.0); typedef long long ll; #define ALL(c) (c).begin(), (c).end() #define CLEAR(v) memset(v,0,sizeof(v)) #define MP(a,b) make_pair((a),(b)) #define REP(i,n) for(int i=0;i<(int)n;++i) #define ABS(a) ((a)>0?(a):-(a)) struct UnionFind { vector data; UnionFind(int size) : data(size, -1) { } bool unionSet(int x, int y) { x = root(x); y = root(y); if (x != y) { if (data[y] < data[x]) swap(x, y); data[x] += data[y]; data[y] = x; } return x != y; } bool findSet(int x, int y) { return root(x) == root(y); } int root(int x) { return data[x] < 0 ? x : data[x] = root(data[x]); } int size(int x) { return -data[root(x)]; } }; void unionSlime(const vector >& a, UnionFind& uf) { REP(i, a.size()) { if (a[i].size() <= 1) { continue; } for (int j = 1; j < a[i].size(); ++j) { uf.unionSet(a[i][0], a[i][j]); } } } int main() { for (int N, W, H; cin >> N >> W >> H && (N || W || H); ) { vector > xs(W); vector > ys(H); bool outline = false; REP(n, N) { int x, y; cin >> x >> y; --x; --y; xs[x].push_back(n); ys[y].push_back(n); outline |= (x == 0); outline |= (y == 0); outline |= (x == W - 1); outline |= (y == H - 1); } UnionFind uf(N); unionSlime(xs, uf); unionSlime(ys, uf); int answer = 0; int numberOfConnectedComponents = 0; REP(n, N) { if (uf.root(n) == n) { answer += uf.size(n) - 1; ++numberOfConnectedComponents; } } if (numberOfConnectedComponents > 1) { answer += numberOfConnectedComponents * 2; --answer; if (outline) { --answer; } } cout << answer << endl; } }