def main():

    import sys

    input = sys.stdin.readline

    sys.setrecursionlimit(10**7)

    from collections import Counter, deque

    from itertools import combinations, permutations, accumulate, groupby, product

    from bisect import bisect_left,bisect_right

    from heapq import heapify, heappop, heappush

    import math

    #from math import gcd



    #inf = 10**17

    #mod = 10**9 + 7



    n = int(eval(input()))

    def find(x):

        if par[x] < 0:

            return x

        else:

            par[x] = find(par[x])

            return par[x]

    

    def unite(x,y):

        x = find(x)

        y = find(y)

        if x == y:

            return False

        else:

            if par[x] > par[y]:

                x,y = y,x

            par[x] += par[y]

            par[y] = x

            return True

    

    def size(x):

        return -par[find(x)]

    

    par = [-1]*(2*10**5+2)

    s = set()

    for _ in range(n):

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

        unite(x, 10**5+y)

        s.add(x)

    

    cnt = Counter()

    for x in s:

        cnt[find(x)] += 1



    res = 0

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

        res += v * (size(k)-v)



    print((res-n))



if __name__ == '__main__':

    main()
def main():

    import sys

    input = sys.stdin.readline

    sys.setrecursionlimit(10**7)

    from collections import Counter, deque

    from itertools import combinations, permutations, accumulate, groupby, product

    from bisect import bisect_left,bisect_right

    from heapq import heapify, heappop, heappush

    import math

    #from math import gcd



    #inf = 10**17

    #mod = 10**9 + 7



    n = int(eval(input()))

    visited_x = [0]*(10**5+1)

    visited_y = [0]*(10**5+1)

    adj_x = [[] for _ in range(10**5+1)]

    adj_y = [[] for _ in range(10**5+1)]



    # 二部グラフにおける隣接点

    for _ in range(n):

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

        adj_x[x].append(y)

        adj_y[y].append(x)



    res = 0

    for x in range(1, 10**5+1):

        if visited_x[x] or not adj_x[x]:

            continue

        visited_x[x] = 1

        vx = 1

        vy = 0

        #[x座標, 軸の方向]

        d = deque([[x, 0]])

        while d:

            v, axis = d.popleft()

            if axis == 0:

                for nv in adj_x[v]:

                    if visited_y[nv]:

                        continue

                    visited_y[nv] = 1

                    vy += 1

                    d.append([nv, 1])

            else:

                for nv in adj_y[v]:

                    if visited_x[nv]:

                        continue

                    visited_x[nv] = 1

                    vx += 1

                    d.append([nv, 0])

        res += vx * vy



    print((res-n))



if __name__ == '__main__':

    main()
def main():
    import sys

    input = sys.stdin.readline
    sys.setrecursionlimit(10**7)
    from collections import Counter, deque
    from itertools import combinations, permutations, accumulate, groupby, product
    from bisect import bisect_left, bisect_right
    from heapq import heapify, heappop, heappush
    import math

    # from math import gcd
    # inf = 10**17
    # mod = 10**9 + 7
    n = int(eval(input()))

    def find(x):
        if par[x] < 0:
            return x
        else:
            par[x] = find(par[x])
            return par[x]

    def unite(x, y):
        x = find(x)
        y = find(y)
        if x == y:
            return False
        else:
            if par[x] > par[y]:
                x, y = y, x
            par[x] += par[y]
            par[y] = x
            return True

    def size(x):
        return -par[find(x)]

    par = [-1] * (2 * 10**5 + 2)
    s = set()
    for _ in range(n):
        x, y = list(map(int, input().split()))
        unite(x, 10**5 + y)
        s.add(x)
    cnt = Counter()
    for x in s:
        cnt[find(x)] += 1
    res = 0
    for k, v in list(cnt.items()):
        res += v * (size(k) - v)
    print((res - n))


if __name__ == "__main__":
    main()

def main():
    import sys

    input = sys.stdin.readline
    sys.setrecursionlimit(10**7)
    from collections import Counter, deque
    from itertools import combinations, permutations, accumulate, groupby, product
    from bisect import bisect_left, bisect_right
    from heapq import heapify, heappop, heappush
    import math

    # from math import gcd
    # inf = 10**17
    # mod = 10**9 + 7
    n = int(eval(input()))
    visited_x = [0] * (10**5 + 1)
    visited_y = [0] * (10**5 + 1)
    adj_x = [[] for _ in range(10**5 + 1)]
    adj_y = [[] for _ in range(10**5 + 1)]
    # 二部グラフにおける隣接点
    for _ in range(n):
        x, y = list(map(int, input().split()))
        adj_x[x].append(y)
        adj_y[y].append(x)
    res = 0
    for x in range(1, 10**5 + 1):
        if visited_x[x] or not adj_x[x]:
            continue
        visited_x[x] = 1
        vx = 1
        vy = 0
        # [x座標, 軸の方向]
        d = deque([[x, 0]])
        while d:
            v, axis = d.popleft()
            if axis == 0:
                for nv in adj_x[v]:
                    if visited_y[nv]:
                        continue
                    visited_y[nv] = 1
                    vy += 1
                    d.append([nv, 1])
            else:
                for nv in adj_y[v]:
                    if visited_x[nv]:
                        continue
                    visited_x[nv] = 1
                    vx += 1
                    d.append([nv, 0])
        res += vx * vy
    print((res - n))


if __name__ == "__main__":
    main()

- -    def find(x): -        if par[x] < 0: -            return x -        else: -            par[x] = find(par[x]) -            return par[x] - -    def unite(x, y): -        x = find(x) -        y = find(y) -        if x == y: -            return False -        else: -            if par[x] > par[y]: -                x, y = y, x -            par[x] += par[y] -            par[y] = x -            return True - -    def size(x): -        return -par[find(x)] - -    par = [-1] * (2 * 10**5 + 2) -    s = set() +    visited_x = [0] * (10**5 + 1) +    visited_y = [0] * (10**5 + 1) +    adj_x = [[] for _ in range(10**5 + 1)] +    adj_y = [[] for _ in range(10**5 + 1)] +    # 二部グラフにおける隣接点 -        unite(x, 10**5 + y) -        s.add(x) -    cnt = Counter() -    for x in s: -        cnt[find(x)] += 1 +        adj_x[x].append(y) +        adj_y[y].append(x) -    for k, v in list(cnt.items()): -        res += v * (size(k) - v) +    for x in range(1, 10**5 + 1): +        if visited_x[x] or not adj_x[x]: +            continue +        visited_x[x] = 1 +        vx = 1 +        vy = 0 +        # [x座標, 軸の方向] +        d = deque([[x, 0]]) +        while d: +            v, axis = d.popleft() +            if axis == 0: +                for nv in adj_x[v]: +                    if visited_y[nv]: +                        continue +                    visited_y[nv] = 1 +                    vy += 1 +                    d.append([nv, 1]) +            else: +                for nv in adj_y[v]: +                    if visited_x[nv]: +                        continue +                    visited_x[nv] = 1 +                    vx += 1 +                    d.append([nv, 0]) +        res += vx * vy