from collections import defaultdict

U = 10 ** 5

root = [None] * (2*U+1)

N = int(eval(input()))

XY = [[int(x) for x in input().split()] for _ in range(N)]



def find_root(x):

  y = root[x]

  if y is None:

    root[x] = x

    return x

  if x == y:

    return y

  z = find_root(y)

  root[x] = z

  return z



def merge(x,y):

  rx = find_root(x)

  ry = find_root(y)

  if rx == ry:

    return

  root[ry] = rx

  return



for x,y in XY:

  merge(x,U+y)



pts_cnt = defaultdict(int)

x_cnt = defaultdict(int)

y_cnt = defaultdict(int)



for x in range(U+1):

  if root[x] is None:

    continue

  x_cnt[find_root(x)] += 1



for y in range(U+1,U+U+1):

  if root[y] is None:

    continue

  y_cnt[find_root(y)] += 1



for x,y in XY:

  pts_cnt[find_root(x)] += 1



answer = 0

for k,v in list(pts_cnt.items()):

  answer += x_cnt[k] * y_cnt[k] - v



print(answer)
import numpy as np

from scipy.sparse import *



U = 10**5

N = int(eval(input()))

XY = np.array([input().split() for _ in range(N)], dtype=np.int32)



graph = csr_matrix((np.ones(N,dtype=np.bool), (XY[:,0], U + XY[:,1])), (2*U+1, 2*U+1))

_, component = csgraph.connected_components(graph)



X_cnt = np.bincount(component[:U+1], minlength = 2*U+2)

Y_cnt = np.bincount(component[U+1:], minlength = 2*U+2)

pts_cnt = np.bincount(component[XY[:,0]], minlength = 2*U+2)

answer = (X_cnt * Y_cnt - pts_cnt).sum()

print(answer)

from collections import defaultdict

U = 10**5
root = [None] * (2 * U + 1)
N = int(eval(input()))
XY = [[int(x) for x in input().split()] for _ in range(N)]


def find_root(x):
    y = root[x]
    if y is None:
        root[x] = x
        return x
    if x == y:
        return y
    z = find_root(y)
    root[x] = z
    return z


def merge(x, y):
    rx = find_root(x)
    ry = find_root(y)
    if rx == ry:
        return
    root[ry] = rx
    return


for x, y in XY:
    merge(x, U + y)
pts_cnt = defaultdict(int)
x_cnt = defaultdict(int)
y_cnt = defaultdict(int)
for x in range(U + 1):
    if root[x] is None:
        continue
    x_cnt[find_root(x)] += 1
for y in range(U + 1, U + U + 1):
    if root[y] is None:
        continue
    y_cnt[find_root(y)] += 1
for x, y in XY:
    pts_cnt[find_root(x)] += 1
answer = 0
for k, v in list(pts_cnt.items()):
    answer += x_cnt[k] * y_cnt[k] - v
print(answer)

import numpy as np
from scipy.sparse import *

U = 10**5
N = int(eval(input()))
XY = np.array([input().split() for _ in range(N)], dtype=np.int32)
graph = csr_matrix(
    (np.ones(N, dtype=np.bool), (XY[:, 0], U + XY[:, 1])), (2 * U + 1, 2 * U + 1)
)
_, component = csgraph.connected_components(graph)
X_cnt = np.bincount(component[: U + 1], minlength=2 * U + 2)
Y_cnt = np.bincount(component[U + 1 :], minlength=2 * U + 2)
pts_cnt = np.bincount(component[XY[:, 0]], minlength=2 * U + 2)
answer = (X_cnt * Y_cnt - pts_cnt).sum()
print(answer)

-from collections import defaultdict +import numpy as np +from scipy.sparse import * -root = [None] * (2 * U + 1) -XY = [[int(x) for x in input().split()] for _ in range(N)] - - -def find_root(x): -    y = root[x] -    if y is None: -        root[x] = x -        return x -    if x == y: -        return y -    z = find_root(y) -    root[x] = z -    return z - - -def merge(x, y): -    rx = find_root(x) -    ry = find_root(y) -    if rx == ry: -        return -    root[ry] = rx -    return - - -for x, y in XY: -    merge(x, U + y) -pts_cnt = defaultdict(int) -x_cnt = defaultdict(int) -y_cnt = defaultdict(int) -for x in range(U + 1): -    if root[x] is None: -        continue -    x_cnt[find_root(x)] += 1 -for y in range(U + 1, U + U + 1): -    if root[y] is None: -        continue -    y_cnt[find_root(y)] += 1 -for x, y in XY: -    pts_cnt[find_root(x)] += 1 -answer = 0 -for k, v in list(pts_cnt.items()): -    answer += x_cnt[k] * y_cnt[k] - v +XY = np.array([input().split() for _ in range(N)], dtype=np.int32) +graph = csr_matrix( +    (np.ones(N, dtype=np.bool), (XY[:, 0], U + XY[:, 1])), (2 * U + 1, 2 * U + 1) +) +_, component = csgraph.connected_components(graph) +X_cnt = np.bincount(component[: U + 1], minlength=2 * U + 2) +Y_cnt = np.bincount(component[U + 1 :], minlength=2 * U + 2) +pts_cnt = np.bincount(component[XY[:, 0]], minlength=2 * U + 2) +answer = (X_cnt * Y_cnt - pts_cnt).sum()