class UnionFind:

    def __init__(self, n):

        self.v = [-1 for _ in range(n)]



    def find(self, x):

        if self.v[x] < 0:  # (負)は根

            return x

        else:

            self.v[x] = self.find(self.v[x])

            return self.v[x]



    def unite(self, x, y):

        x = self.find(x)

        y = self.find(y)

        if x == y:

            return

        if -self.v[x] < -self.v[y]:

            x, y = y, x

        self.v[x] += self.v[y]

        self.v[y] = x



    def root(self, x):

        return self.v[x] < 0



    def size(self, x):

        return -self.v[self.find(x)]





mx = 10 ** 5 + 10



n = int(eval(input()))



uf = UnionFind(mx * 2)



for _ in range(n):

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

    uf.unite(x, y + mx)



vx = [0] * (mx * 2)

vy = [0] * (mx * 2)



for i in range(mx):

    root = uf.find(i)

    vx[root] += 1



for i in range(mx, mx * 2):

    root = uf.find(i)

    vy[root] += 1



ans = -n

for xx, yy in zip(vx, vy):

    ans += xx * yy

print(ans)

# https://drken1215.hatenablog.com/entry/2019/06/23/004700

# https://tjkendev.github.io/procon-library/python/union_find/union_find.html



def main():

    import sys

    input = sys.stdin.readline



    MX = 10 ** 5 + 10

    

    *p, = [r for r in range(MX * 2)]



    def root(x):

        if x == p[x]:

            return x

        p[x] = y = root(p[x])

        return y



    def unite(x, y):

        px = root(x)

        py = root(y)

        if px == py:

            return 0

        if px < py:

            p[py] = px

        else:

            p[px] = py

        return 1



    n = int(eval(input()))

    for _ in range(n):

        x, y = (int(x) - 1 for x in input().split())  # [1,)->[0,)

        unite(x, y + MX)



    xs = [0] * (MX * 2)

    ys = [0] * (MX * 2)



    for r in range(MX):

        xs[root(r)] += 1



    for r in range(MX, MX * 2):

        ys[root(r)] += 1



    ans = -n

    for r in range(MX * 2):

        ans += xs[r] * ys[r]



    print(ans)





if __name__ == '__main__':

    main()

class UnionFind:
    def __init__(self, n):
        self.v = [-1 for _ in range(n)]

    def find(self, x):
        if self.v[x] < 0:  # (負)は根
            return x
        else:
            self.v[x] = self.find(self.v[x])
            return self.v[x]

    def unite(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return
        if -self.v[x] < -self.v[y]:
            x, y = y, x
        self.v[x] += self.v[y]
        self.v[y] = x

    def root(self, x):
        return self.v[x] < 0

    def size(self, x):
        return -self.v[self.find(x)]


mx = 10**5 + 10
n = int(eval(input()))
uf = UnionFind(mx * 2)
for _ in range(n):
    x, y = list(map(int, input().split()))
    uf.unite(x, y + mx)
vx = [0] * (mx * 2)
vy = [0] * (mx * 2)
for i in range(mx):
    root = uf.find(i)
    vx[root] += 1
for i in range(mx, mx * 2):
    root = uf.find(i)
    vy[root] += 1
ans = -n
for xx, yy in zip(vx, vy):
    ans += xx * yy
print(ans)

# https://drken1215.hatenablog.com/entry/2019/06/23/004700
# https://tjkendev.github.io/procon-library/python/union_find/union_find.html
def main():
    import sys

    input = sys.stdin.readline
    MX = 10**5 + 10
    (*p,) = [r for r in range(MX * 2)]

    def root(x):
        if x == p[x]:
            return x
        p[x] = y = root(p[x])
        return y

    def unite(x, y):
        px = root(x)
        py = root(y)
        if px == py:
            return 0
        if px < py:
            p[py] = px
        else:
            p[px] = py
        return 1

    n = int(eval(input()))
    for _ in range(n):
        x, y = (int(x) - 1 for x in input().split())  # [1,)->[0,)
        unite(x, y + MX)
    xs = [0] * (MX * 2)
    ys = [0] * (MX * 2)
    for r in range(MX):
        xs[root(r)] += 1
    for r in range(MX, MX * 2):
        ys[root(r)] += 1
    ans = -n
    for r in range(MX * 2):
        ans += xs[r] * ys[r]
    print(ans)


if __name__ == "__main__":
    main()

-class UnionFind: -    def __init__(self, n): -        self.v = [-1 for _ in range(n)] +# https://drken1215.hatenablog.com/entry/2019/06/23/004700 +# https://tjkendev.github.io/procon-library/python/union_find/union_find.html +def main(): +    import sys -    def find(self, x): -        if self.v[x] < 0:  # (負)は根 +    input = sys.stdin.readline +    MX = 10**5 + 10 +    (*p,) = [r for r in range(MX * 2)] + +    def root(x): +        if x == p[x]: +        p[x] = y = root(p[x]) +        return y + +    def unite(x, y): +        px = root(x) +        py = root(y) +        if px == py: +            return 0 +        if px < py: +            p[py] = px -            self.v[x] = self.find(self.v[x]) -            return self.v[x] +            p[px] = py +        return 1 -    def unite(self, x, y): -        x = self.find(x) -        y = self.find(y) -        if x == y: -            return -        if -self.v[x] < -self.v[y]: -            x, y = y, x -        self.v[x] += self.v[y] -        self.v[y] = x - -    def root(self, x): -        return self.v[x] < 0 - -    def size(self, x): -        return -self.v[self.find(x)] +    n = int(eval(input())) +    for _ in range(n): +        x, y = (int(x) - 1 for x in input().split())  # [1,)->[0,) +        unite(x, y + MX) +    xs = [0] * (MX * 2) +    ys = [0] * (MX * 2) +    for r in range(MX): +        xs[root(r)] += 1 +    for r in range(MX, MX * 2): +        ys[root(r)] += 1 +    ans = -n +    for r in range(MX * 2): +        ans += xs[r] * ys[r] +    print(ans) -mx = 10**5 + 10 -n = int(eval(input())) -uf = UnionFind(mx * 2) -for _ in range(n): -    x, y = list(map(int, input().split())) -    uf.unite(x, y + mx) -vx = [0] * (mx * 2) -vy = [0] * (mx * 2) -for i in range(mx): -    root = uf.find(i) -    vx[root] += 1 -for i in range(mx, mx * 2): -    root = uf.find(i) -    vy[root] += 1 -ans = -n -for xx, yy in zip(vx, vy): -    ans += xx * yy -print(ans) +if __name__ == "__main__": +    main()