//----AUTHOR:kkdrummer----/
#include<bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
using namespace std;
typedef    long long   ll;
typedef    long double   ld;
//typedef    unordered_set<ll>   usll;
//typedef    unordered_multiset<ll>   umsll;
typedef    multiset<ll>   msll;
typedef    set<ll>   sll;
typedef    vector<ll>   vll;
typedef    pair<ll,ll>   pll;
typedef    vector<pll>   vpll;
typedef    priority_queue<ll>   pqll;
typedef    vector<int>   vi;
typedef    set<int>   si;
typedef    multiset<int>   msi;
//typedef    unordered_multiset<int>   umsi;
//typedef    unordered_set<int>   usi;
typedef     pair<int,int>   pi;
typedef    vector<pi>   vpi;
typedef    set<pi>   spi;
typedef    priority_queue<int>   pqi;
typedef    tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update>   ind_set;
typedef    tree<ll,null_type,less<ll>,rb_tree_tag,tree_order_statistics_node_update>   ind_setll;
#define    in   insert
#define    fi   first
#define    se   second
#define    pb   push_back
#define    mp   make_pair
#define    be   begin
#define    en   end
#define    itr   iterator
#define io ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
#define    mo   1000000007
#define    inf  9223372036854775807
#define    ninf   -inf
#define    ima   2147483647
#define    imi   -ima
#define    oncnt    __builtin_popcount
#define    zerobegin   __builtin_clz
#define    zeroend   __builtin_ctz
#define    parity   __builtin_parity
#define    all(x)   x.be(),x.en()
#define    eps   1e-9
#define    coutd   cout<<setprecision(10)<<fixed
#define    mems(dp,x)   memset(dp,x,sizeof(dp))
const    ld   PI=3.14159265359;
inline ll modpow(ll x,ll n){if(n==0)return 1;if(n==1)return(x%mo);ll u=(modpow(x,n/2));u=(u*u)%mo;if(n%2!=0)u=(u*x%mo)%mo;return u;}
inline ll modinv(ll x){return modpow(x,mo-2);}
inline ll mmul(ll a,ll b){    if(a>=mo)a=a%mo;if(b>=mo)b=b%mo;if(a*b>=mo)return(a*b)%mo;return(a*b);}
inline ll madd(ll a, ll b){if(a>=mo)a=a%mo;if(b>=mo)b=b%mo;if(a+b>=mo)return(a+b)%mo;return(a+b);}
inline ll msub(ll a, ll b){if(a>=mo)a=a%mo;if(b>=mo)b=b%mo;return(((a-b)%mo+mo)%mo);}
inline ll mdiv(ll a,ll bb){if(a>=mo)a=a%mo;ll b=modinv(bb);if(b>=mo)b=b%mo;if(a*b>=mo)return(a*b)%mo;return(a*b);}
inline ll gcd(ll a,ll b){return __gcd(a,b);}

void dfsfillorder (vector<int> adj[],stack<int> &s,int u,bool visited[])
{
	if(visited[u])
	return ;
	visited[u]=true;
for(int i=0;i<adj[u].size();i++)
dfsfillorder(adj,s,adj[u][i],visited);
		s.push(u);
}

void rev(vector<int> adjr[],vector<int> adj[],int v)
{for(int i=1;i<=v;i++)
	{for(int j=0;j<adj[i].size();j++)
	adjr[adj[i][j]].push_back(i);
}
}

void dfsutil(vector<int> adj[],stack<int> &s,int x,bool visited[],vector<int> &vx)
{
	if(!visited[x])
	{vx.push_back(x);
		visited[x]=true;
		for(int i=0;i<adj[x].size();i++)
		dfsutil(adj,s,adj[x][i],visited,vx);		
	}	
}

vector<vector<int> > getSCC(vector<int> adj[],int v)
{
	vector<vector<int> > cc;
	stack<int> s;
	bool visited[v+1]={false};
	for(int i=1;i<=v;i++)
	dfsfillorder(adj,s,i,visited);
		
	vector<int> adjr[v+1];
	rev(adjr,adj,v);

	for(int i=1;i<=v;i++)
	visited[i]=false;
	
	while(!s.empty())
	{   int x=s.top();
		s.pop();
		if(!visited[x])
		{
		vector<int> vx;
		dfsutil(adjr,s,x,visited,vx);
		 cc.push_back(vx);
	    } 
	}

return cc;		
}



int main()
{
io
int testcases=1;//cin>>testcases;
while(testcases--)
{
	
int n;

cin>>n;
vi ad[2*n+1];
int nn=n;
int id=1;
int m[100001]={0};
 map<int,int> xs,ys;
while(nn--)
{
	int x,y;
	cin>>x>>y;
	if(xs.find(x)==xs.end())
	{
		xs[x]=id;
		m[id]=1;
		id++;
	}
	if(ys.find(y)==ys.end())
	{
		ys[y]=id;
		id++;
	}
	int a=xs[x];
	int b=ys[y];
	ad[a].pb(b);
	ad[b].pb(a);
}

vector<vector<int> > cc=getSCC(ad,id-1);

ll ans=0;

for(int i=0;i<cc.size();i++)
{ll prev=0;
ll xp=0,yp=0;
	for(int j=0;j<cc[i].size();j++)
	{
		int k=cc[i][j];
		if(m[k]==1)
		{
			xp++;
			prev+=ad[k].size();
		}
		else
		{
			yp++;
		}
	}
	ans+=((xp*yp)-prev);
	//cout<<xp<<" "<<yp<<" "<<prev<<"\n";
}

cout<<ans;

}return 0;}

Measured memory_bytes: 26232