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 <algorithm>
#include <iostream>
#include <map>
#include <numeric>
#include <set>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <queue>
#define MOD (1000000007l)
#define rep(i, n) for(long i = 0; i < n; i++)

using namespace std;

long union_find_find(long num, vector<long> &vec) {
  // cout << "num: " << num << endl;
  if (vec[num] == -1) return num;
  long ret = union_find_find(vec[num], vec);
  vec[num] = ret;
  return ret;
}

unordered_map<long, unordered_set<long>> same_x_group;
unordered_map<long, unordered_set<long>> same_y_group;

unordered_map<long, unordered_set<long>> xs;
unordered_map<long, unordered_set<long>> ys;
unordered_set<long> roots;

void solve() {
  long N;
  cin >> N;

  vector<long> vec(N, -1);
  rep(i, N) vec[i] = -1;
  vector<pair<long, long>> points(N);

  // cout << "foo 1" << endl;

  rep (i, N) {
    long x, y;
    cin >> x >> y;
    same_x_group[x].insert(i);
    same_y_group[y].insert(i);
    points[i] = make_pair(x, y);
  }

  // cout << "foo 2" << endl;

  for (auto _it = same_x_group.begin(); _it != same_x_group.end(); _it++) {
    long tmp_root = *(_it->second.begin());
    for (auto it = _it->second.begin(); it != _it->second.end(); it++) {
      if (it == _it->second.begin()) continue;
      long node = *it;
      vec[node] = tmp_root;
    }
  }

  // cout << "foo 3" << endl;

  for (auto _it = same_y_group.begin(); _it != same_y_group.end(); _it++) {
    long first_node = *(_it->second.begin());
    // cout << "first_node: " << first_node << endl;
    long first_node_root = union_find_find(first_node, vec);
    // cout << "first_node_root: " << first_node_root << endl;
    for (auto it = _it->second.begin(); it != _it->second.end(); it++) {
      if (it == _it->second.begin()) continue;
      long current_node = *it;
      // cout << "current_node: " << current_node << endl;
      long current_node_root = union_find_find(current_node, vec);
      // cout << "current_node_root: " << current_node_root << endl;
      if (current_node_root != first_node_root) vec[current_node_root] = first_node_root;
    }
  }

  // cout << "foo 4" << endl;

  rep (i, N) {
    long root = union_find_find(i, vec);
    xs[root].insert(points[i].first);
    ys[root].insert(points[i].second);
    roots.insert(root);
  }

  // cout << "foo 5" << endl;

  long maximum_points = 0;

  for (auto r: roots) {
    maximum_points += xs[r].size() * ys[r].size();
  }

  // cout << "foo 6" << endl;

  cout << maximum_points - N << endl;
}

int main(void) {
  cin.tie(0);
  ios::sync_with_stdio(false);
  cout.precision(12);
  solve();
  return 0;
}