Problem:
Score : 600 points

Problem Statement

There are N dots in a two-dimensional plane. The coordinates of the i-th dot are (x_i, y_i).

We will repeat the following operation as long as possible:

Choose four integers a, b, c, d (a \neq c, b \neq d) such that there are dots at exactly three of the positions (a, b), (a, d), (c, b) and (c, d), and add a dot at the remaining position.

We can prove that we can only do this operation a finite number of times. Find the maximum number of times we can do the operation.

Constraints

1 \leq N \leq 10^5

1 \leq x_i, y_i \leq 10^5

If i \neq j, x_i \neq x_j or y_i \neq y_j.

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N
x_1 y_1
:
x_N y_N

Output

Print the maximum number of times we can do the operation.

Sample Input 1

3
1 1
5 1
5 5

Sample Output 1

1

By choosing a = 1, b = 1, c = 5, d = 5, we can add a dot at (1, 5). We cannot do the operation any more, so the maximum number of operations is 1.

Sample Input 2

2
10 10
20 20

Sample Output 2

0

There are only two dots, so we cannot do the operation at all.

Sample Input 3

9
1 1
2 1
3 1
4 1
5 1
1 2
1 3
1 4
1 5

Sample Output 3

16

We can do the operation for all choices of the form a = 1, b = 1, c = i, d = j (2 \leq i,j \leq 5), and no more. Thus, the maximum number of operations is 16.

Solution in C++14 (GCC 5.4.1) (judge verdict: Accepted)

#include <bits/stdc++.h>
using namespace std;
using Int = int_fast64_t;

Int n;
using P = pair<Int, Int>;
vector<P> v;
vector<Int> xs, ys;
class unionfind{ // 0-indexed
public:
	vector<int> parent;
	vector<size_t> size;
	size_t num_of_disjointsets;
	unionfind(size_t n){
		parent.resize(n, -1);
		size.resize(n, 1);
		num_of_disjointsets = n;
	}

	size_t find(size_t x){
		if(parent[x] == -1) return x;
		return parent[x] = find(parent[x]);
	}

	size_t unite(size_t x, size_t y){
		x = find(x);
		y = find(y);
		if(x == y) return -1;
		if(size[x] < size[y]){
			parent[x] = y;
			size[y] += size[x];
			size[x] = 0;
			--num_of_disjointsets;
			return y;
		}else{
			parent[y] = x;
			size[x] += size[y];
			size[y] = 0;
			return x;
			--num_of_disjointsets;
		}
	}

	bool united(size_t x, size_t y){
		return find(x) == find(y);
	}
};

int main(){
	cin.tie(0);
	ios::sync_with_stdio(false);
	cin >> n;
	for(Int i=0; i<n; ++i){
		Int x, y; cin >> x >> y;
		v.push_back(P(x, y));
		xs.push_back(x);
		ys.push_back(y);
	}
	sort(xs.begin(), xs.end());
	sort(ys.begin(), ys.end());
	xs.erase(unique(xs.begin(), xs.end()), xs.end());
	ys.erase(unique(ys.begin(), ys.end()), ys.end());
	for(Int i=0; i<n; ++i){
		v[i].first = lower_bound(xs.begin(), xs.end(), v[i].first)-xs.begin();
		v[i].second = lower_bound(ys.begin(), ys.end(), v[i].second)-ys.begin();
	}
	unionfind uf(xs.size()+ys.size());
	for(Int i=0; i<n; ++i)
		uf.unite(v[i].first, xs.size()+v[i].second);
	vector<Int> num(xs.size()+ys.size()), nx(xs.size()+ys.size()), ny(xs.size()+ys.size());
	for(Int i=0; i<n; ++i) ++num[uf.find(v[i].first)];
	for(size_t i=0; i<xs.size(); ++i) ++nx[uf.find(i)];
	for(size_t i=0; i<ys.size(); ++i) ++ny[uf.find(xs.size()+i)];
	Int ans = 0;
	for(size_t i=0; i<xs.size()+ys.size(); ++i)
		if(uf.find(i) == i)
			ans += nx[i] * ny[i] - num[i];
	cout << ans << "\n";
/*	for(Int i=0; i<n; ++i)
		cerr << v[i].first << " " << v[i].second << "\n";
	for(size_t i=0; i<nx.size(); ++i)
		cerr << nx[i] << " \n"[i+1==nx.size()];
	for(size_t i=0; i<ny.size(); ++i)
		cerr << ny[i] << " \n"[i+1==ny.size()];*/
}