#pragma once
#include <stdio.h>
#include <sstream>
#include <string>
#include <string.h>
#include <vector>
#include <map>
#include <algorithm>
#include <iostream>
#include <utility>
#include <set>
#include <cctype>
#include <queue>
#include <stack>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <deque>
#include <limits>
#include <iomanip>
#define _USE_MATH_DEFINES
#include <math.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
#define bit(x,v) ((ll)x << v)

const ll INF = 1000000007;
const int MAX = 210000;
const int MOD = 1000000007;

long long fac[MAX], finv[MAX], inv[MAX];
void COMinit() {
	fac[0] = fac[1] = 1;
	finv[0] = finv[1] = 1;
	inv[1] = 1;
	for (int i = 2; i < MAX; i++) {
		fac[i] = fac[i - 1] * i % MOD;
		inv[i] = MOD - inv[MOD % i] * (MOD / i) % MOD;
		finv[i] = finv[i - 1] * inv[i] % MOD;
	}
}

// 二項係数計算
long long COM(int n, int k) {
	if (n < k) return 0;
	if (n < 0 || k < 0) return 0;
	return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD;
}

ll gcd(ll a, ll b) {
	if (b == 0) return a;
	return gcd(b, a % b);
}
int pr[100010];
void uini(int n) {
	for (size_t i = 0; i <= n; i++)
	{
		pr[i] = i;
	}
}

int parent(int x) {
	if (x == pr[x]) return x;
	return pr[x] = parent(pr[x]);
}

bool unit(int x, int y) {
	int px = parent(x);
	int py = parent(y);

	if (px == py) return false;
	if (px < py) {
		pr[py] = px;
	}
	else {
		pr[px] = py;
	}
	return true;
}

// res[i][c] := i 文字目以降で最初に文字 c が登場する index (存在しないときは n)
vector<vector<int> > calcNext(const string& S) {
	int n = (int)S.size();
	vector<vector<int> > res(n + 1, vector<int>(26, n));
	for (int i = n - 1; i >= 0; --i) {
		for (int j = 0; j < 26; ++j) res[i][j] = res[i + 1][j];
		res[i][S[i] - 'a'] = i;
	}
	return res;
}
vector<int> es[100010];
int d1[100010];
ll lev1[100010];

int d2[100010];
ll lev2[100010];
ll edg[100010];
int parent(int* d, int x) {
	if (d[x] == x) return x;
	return d[x] = parent(d,d[x]);
}
void uinit(int *d,int n) {
	for (size_t i = 0; i <= n; i++)
	{
		d[i] = i;
	}
}
void unite(int *d,ll *lev,int x, int y) {
	int px = parent(d,x);
	int py = parent(d,y);

	if (px == py) return;
	if (lev[px] < lev[py]) {
		d[px] = py;
		lev[py] += lev[px];		
	}
	else {
		d[py] = px;
		lev[px] += lev[py];
	}
}
vector<int> es1[100010];
vector<int> es2[100010];

void solv() {
	
	ll n;
	cin >> n;
	uinit(d1, 100010);
	uinit(d2, 100010);

	for (size_t i = 0; i < n; i++)
	{
		int x, y;
		cin >> x >> y;
		if (parent(d1, x) == x && lev1[x] == 0) {
			lev1[x]++;
		}

		if (parent(d2, y) == y && lev2[y] == 0) {
			lev2[y]++;
		}

		if (es2[y].size() > 0) {
			ll py = parent(d1,es2[y][0]);
			ll px = parent(d1, x);
			unite(d1,lev1,x, es2[y][0]);
			if(py != px)
				edg[px] = edg[py] = (edg[py] + edg[px]);
		}

		if (es1[x].size() > 0) {
			unite(d2, lev2, y, es1[x][0]);
		}

		es1[x].push_back(y);
		es2[y].push_back(x);
		
		edg[parent(d1, x)]++;
	}
	
	bool use[100010];
	memset(use, 0, sizeof(use));
	ll res = 0;
	for (size_t i = 1; i <= 100000; i++)
	{
		if (es1[i].size() == 0) continue;
		ll xp = parent(d1,i);
		if (use[xp]) continue;
		ll yp = parent(d2,es1[i][0]);
		use[xp] = true;
		res += ((lev1[xp]) * (lev2[yp])) - edg[xp];
	}
	cout << res << endl;
}

int main() {
	COMinit();
	solv();

	return 0;
}
 

Measured memory_bytes: 18944