unittest
{
	assert( [ "4", "1 1", "5 1", "1 5", "5 5" ].parse.expand.solve == 0 );		// 追加ケース
	
	assert( [ "3", "1 1", "5 1", "5 5" ].parse.expand.solve == 1 );
	assert( [ "2", "10 10", "20 20" ].parse.expand.solve == 0 );
	assert( [ "9", "1 1", "2 1", "3 1", "4 1", "5 1", "1 2", "1 3", "1 4", "1 5" ].parse.expand.solve == 16 );
}



import std.algorithm;
import std.conv;
import std.range;
import std.stdio;
import std.typecons;

void main()
{
	stdin.byLineCopy.parse.expand.solve.writeln;
}

auto parse( Range )( Range input )
if( isInputRange!Range && is( ElementType!Range == string ) )
{
	auto n = input.front.to!( long );
	auto xyis = new long[ 3 ][ n ];
	foreach( i, ref xyi; xyis )
	{
		input.popFront;
		xyi = input.front.split.to!( long[] ) ~ i;
	}
	return tuple( xyis );
}

auto solve( long[ 3 ][] xyis )
{
	// X座標orY座標が同じ頂点を同じ集合にまとめる
	auto uft = UnionFindTree( xyis.length );
	long[ 3 ] p = [ -1L, -1L, -1L ];
	foreach( xyi; xyis.sort() )
	{
		if( p[ 0 ] == xyi[ 0 ] ) uft.unite( p[ 2 ], xyi[ 2 ] );
		else                     p = xyi;
	}
	foreach( xyi; xyis.sort!( ( p, xyi ) => p[ 1 ] < xyi[ 1 ] ) )
	{
		if( p[ 1 ] == xyi[ 1 ] ) uft.unite( p[ 2 ], xyi[ 2 ] );
		else                     p = xyi;
	}
	
	// 各集合ごとにx座標とy座標の種類数を集計
	bool[ long ][ long ] xys;
	bool[ long ][ long ] rxs;
	bool[ long ][ long ] rys;
	foreach( xyi; xyis )
	{
		auto r = uft.root( xyi[ 2 ] );
		xys[ xyi[ 0 ] ][ xyi[ 1 ] ] = true;
		rxs[ r ][ xyi[ 0 ] ] = true;
		rys[ r ][ xyi[ 1 ] ] = true;
	}
	
	// 各集合ごとに追加できる頂点の数を計算
	auto ans = 0L;
	foreach( r; rxs.keys )
	{
		foreach( x; rxs[ r ].keys )
		{
			foreach( y; rys[ r ].keys )
			{
				if( x !in xys || y !in xys[ x ] ) ans++;
			}
		}
	}
	return ans;
}

// UnionFind木
struct UnionFindTree
{
	private long[] ps;
	private long[] rs;
	
	public this( long n )
	{
		ps.length = n;
		ps[] = -1;
		rs.length = n;
	}
	
	public long root( long i )
	{
		if( ps[ i ] < 0 ) return i;
		else              return ps[ i ] = root( ps[ i ] );
	}
	
	public bool same( long i, long j )
	{
		return root( i ) == root( j );
	}
	
	public void unite( long i, long j )
	{
		i = root( i );
		j = root( j );
		if( i == j ) return;
		if( rs[ i ] < rs[ j ] )
		{
			ps[ j ] += ps[ i ];
			ps[ i ] = j;
		}
		else
		{
			ps[ i ] += ps[ j ];
			ps[ j ] = i;
			if( rs[ i ] == rs[ j ] ) rs[ i ]++;
		}
	}
}
