import sys

sys.setrecursionlimit(10**6)



def dfs(x, al):

    global cntx, cnty

    if (al, x) in used:

        return

    used.add((al, x))

    if al == 0:

        cntx += 1

    else:

        cnty += 1

    for xy in to[al][x]:

        dfs(xy, 1 - al)

    return



n = int(eval(input()))

to = [{}, {}]

for _ in range(n):

    x, y = list(map(int, input().split()))

    to[0].setdefault(x, [])

    to[1].setdefault(y, [])

    to[0][x] += [y]

    to[1][y] += [x]

used = set()

ans = 0

for x in list(to[0].keys()):

    if (0, x) in used: continue

    cntx = 0

    cnty = 0

    dfs(x, 0)

    ans += cntx * cnty

print((ans - n))

def get_group(x):

    g = group[x]

    if g == x:

        return x

    group[g] = re = get_group(g)

    return re



def unite(x, y):

    gx = get_group(x)

    gy = get_group(y)

    if gx != gy:

        dx = depth[gx]

        dy = depth[gy]

        if dy > dx:

            gx, gy = gy, gx

        group[gy] = gx

        if dx == dy:

            depth[gx] += 1



n = int(eval(input()))

group = {}

depth = {}

edge = []

for _ in range(n):

    x, y = list(map(int, input().split()))

    group.setdefault(x, x)

    group.setdefault(-y, -y)

    depth.setdefault(x, 1)

    depth.setdefault(-y, 1)

    edge += [[x, -y]]



for x, y in edge:

    unite(x, y)



cnt = {}

for k in list(group.keys()):

    g = get_group(k)

    cnt.setdefault(g, [0, 0])

    if k > 0:

        cnt[g][0] += 1

    else:

        cnt[g][1] += 1



ans = 0

for cx, cy in list(cnt.values()):

    ans += cx * cy

print((ans - n))

import sys

sys.setrecursionlimit(10**6)


def dfs(x, al):
    global cntx, cnty
    if (al, x) in used:
        return
    used.add((al, x))
    if al == 0:
        cntx += 1
    else:
        cnty += 1
    for xy in to[al][x]:
        dfs(xy, 1 - al)
    return


n = int(eval(input()))
to = [{}, {}]
for _ in range(n):
    x, y = list(map(int, input().split()))
    to[0].setdefault(x, [])
    to[1].setdefault(y, [])
    to[0][x] += [y]
    to[1][y] += [x]
used = set()
ans = 0
for x in list(to[0].keys()):
    if (0, x) in used:
        continue
    cntx = 0
    cnty = 0
    dfs(x, 0)
    ans += cntx * cnty
print((ans - n))

def get_group(x):
    g = group[x]
    if g == x:
        return x
    group[g] = re = get_group(g)
    return re


def unite(x, y):
    gx = get_group(x)
    gy = get_group(y)
    if gx != gy:
        dx = depth[gx]
        dy = depth[gy]
        if dy > dx:
            gx, gy = gy, gx
        group[gy] = gx
        if dx == dy:
            depth[gx] += 1


n = int(eval(input()))
group = {}
depth = {}
edge = []
for _ in range(n):
    x, y = list(map(int, input().split()))
    group.setdefault(x, x)
    group.setdefault(-y, -y)
    depth.setdefault(x, 1)
    depth.setdefault(-y, 1)
    edge += [[x, -y]]
for x, y in edge:
    unite(x, y)
cnt = {}
for k in list(group.keys()):
    g = get_group(k)
    cnt.setdefault(g, [0, 0])
    if k > 0:
        cnt[g][0] += 1
    else:
        cnt[g][1] += 1
ans = 0
for cx, cy in list(cnt.values()):
    ans += cx * cy
print((ans - n))

-import sys - -sys.setrecursionlimit(10**6) +def get_group(x): +    g = group[x] +    if g == x: +        return x +    group[g] = re = get_group(g) +    return re -def dfs(x, al): -    global cntx, cnty -    if (al, x) in used: -        return -    used.add((al, x)) -    if al == 0: -        cntx += 1 -    else: -        cnty += 1 -    for xy in to[al][x]: -        dfs(xy, 1 - al) -    return +def unite(x, y): +    gx = get_group(x) +    gy = get_group(y) +    if gx != gy: +        dx = depth[gx] +        dy = depth[gy] +        if dy > dx: +            gx, gy = gy, gx +        group[gy] = gx +        if dx == dy: +            depth[gx] += 1 -to = [{}, {}] +group = {} +depth = {} +edge = [] -    to[0].setdefault(x, []) -    to[1].setdefault(y, []) -    to[0][x] += [y] -    to[1][y] += [x] -used = set() +    group.setdefault(x, x) +    group.setdefault(-y, -y) +    depth.setdefault(x, 1) +    depth.setdefault(-y, 1) +    edge += [[x, -y]] +for x, y in edge: +    unite(x, y) +cnt = {} +for k in list(group.keys()): +    g = get_group(k) +    cnt.setdefault(g, [0, 0]) +    if k > 0: +        cnt[g][0] += 1 +    else: +        cnt[g][1] += 1 -for x in list(to[0].keys()): -    if (0, x) in used: -        continue -    cntx = 0 -    cnty = 0 -    dfs(x, 0) -    ans += cntx * cnty +for cx, cy in list(cnt.values()): +    ans += cx * cy