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 (GCC 5.4.1) (judge verdict: Accepted)

#include<stdio.h>
#include<stdlib.h>
#include<stdint.h>
#include<inttypes.h>

typedef struct union_find {
  int32_t *parent;
  int32_t size;
} union_find;

void init_union_find (union_find * const u) {
  for (int32_t i = 0; i < u->size; ++i){
    u->parent[i] = -1;
  }
}

union_find* new_union_find (const int32_t size) {
  union_find * const u = (union_find *) calloc (1, sizeof (union_find));
  u->parent = (int32_t *) calloc (size, sizeof (int32_t));
  u->size = size;
  init_union_find (u);
  return u;
}

void free_union_find (union_find * const u) {
  free (u->parent);
  free (u);
}

int32_t root (union_find * const u, int32_t x) {
  int32_t index[32];
  int32_t top = 0;
  while (u->parent[x] >= 0) {
    index[top++] = x;
    x = u->parent[x];
  }
  while (top > 0) {
    u->parent[index[--top]] = x;
  }
  return x;
}

int same (union_find * const u, const int32_t x, const int32_t y) {
  return root (u, x) == root (u, y);
}

int32_t get_size (union_find * const u, const int32_t x) {
  return - (u->parent[root (u, x)]);
}

void unite (union_find * const u, int32_t x, int32_t y) {
  x = root (u, x);
  y = root (u, y);
  if (x == y) return;
  if (u->parent[x] > u->parent[y]) {
    const int32_t swap = x;
    x = y;
    y = swap;
  }
  u->parent[x] += u->parent[y];
  u->parent[y] = x;
}

typedef int32_t i32;
typedef int64_t i64;

#define ALLOC(size,type) ((type*)calloc((size),sizeof(type)))
#define SORT(a,num,cmp) qsort((a),(num),sizeof(*(a)),cmp)

typedef struct point {
  i32 x, y;
} point;

int cmp_x (const void *a, const void *b) {
  i32 d = ((point *)a)->x - ((point *)b)->x;
  return d == 0 ? 0 : d < 0 ? -1 : 1;
}

int cmp_y (const void *a, const void *b) {
  i32 d = ((point *)a)->y - ((point *)b)->y;
  return d == 0 ? 0 : d < 0 ? -1 : 1;
}

void run (void) {
  i32 n;
  scanf ("%" SCNi32, &n);
  const i32 m = 100001;
  point *p = ALLOC (n, point);
  for (i32 i = 0; i < n; ++i) {
    i32 x, y;
    scanf ("%" SCNi32 "%" SCNi32, &x, &y);
    p[i] = (point) {x, y};
  }
  SORT (p, n, cmp_x);
  union_find *uy = new_union_find (m);
  for (i32 i = 0; i < n;) {
    for (++i; i < n && p[i - 1].x == p[i].x; ++i) {
      unite (uy, p[i].y, p[i - 1].y);
    }
  }
  SORT (p, n, cmp_y);
  union_find *ux = new_union_find (m);
  for (i32 i = 0; i < n;) {
    for (++i; i < n && p[i - 1].y == p[i].y; ++i) {
      unite (ux, p[i].x, p[i - 1].x);
    }
  }
  i32 *used = ALLOC (m, i32);
  i64 ans = 0;
  for (i32 i = 0; i < n; ++i) {
    i32 r = root (ux, p[i].x);
    if (used[r]) continue;
    used[r] = 1;
    ans += (i64) get_size (ux, p[i].x) * get_size (uy, p[i].y);
  }
  ans -= n;
  printf ("%" PRIi64 "\n", ans);
}

int main (void) {
  run();
  return 0;
}