Problem:
Score : 600 points

Problem Statement

There are N dots in a two-dimensional plane. The coordinates of the i-th dot are (x_i, y_i).

We will repeat the following operation as long as possible:

Choose four integers a, b, c, d (a \neq c, b \neq d) such that there are dots at exactly three of the positions (a, b), (a, d), (c, b) and (c, d), and add a dot at the remaining position.

We can prove that we can only do this operation a finite number of times. Find the maximum number of times we can do the operation.

Constraints

1 \leq N \leq 10^5

1 \leq x_i, y_i \leq 10^5

If i \neq j, x_i \neq x_j or y_i \neq y_j.

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N
x_1 y_1
:
x_N y_N

Output

Print the maximum number of times we can do the operation.

Sample Input 1

3
1 1
5 1
5 5

Sample Output 1

1

By choosing a = 1, b = 1, c = 5, d = 5, we can add a dot at (1, 5). We cannot do the operation any more, so the maximum number of operations is 1.

Sample Input 2

2
10 10
20 20

Sample Output 2

0

There are only two dots, so we cannot do the operation at all.

Sample Input 3

9
1 1
2 1
3 1
4 1
5 1
1 2
1 3
1 4
1 5

Sample Output 3

16

We can do the operation for all choices of the form a = 1, b = 1, c = i, d = j (2 \leq i,j \leq 5), and no more. Thus, the maximum number of operations is 16.

Solution in C# (Mono 4.6.2.0) (judge verdict: Time Limit Exceeded)

using System;
using System.Collections.Generic;
using System.Linq;
using MustBeRectangular;

namespace MustBeRectangular
{
    public class Point
    {
        int x;
        int y;

        public int X { get { return x; } set { x = value; } }
        public int Y { get { return y; } set { y = value; } }

        public Point(int x, int y)
        {
            this.x = x;
            this.y = y;
        }
    }

    public static class Combination
    {
        public static IEnumerable<T[]> Enumerate<T>(IEnumerable<T> items, int k, bool withRepetition)
        {
            if (k == 1)
            {
                foreach (var item in items)
                    yield return new T[] { item };
                yield break;
            }
            foreach (var item in items)
            {
                var leftside = new T[] { item };

                // item よりも前のものを除く （順列と組み合わせの違い)
                // 重複を許さないので、unusedから item そのものも取り除く
                var unused = withRepetition ? items : items.SkipWhile(e => !e.Equals(item)).Skip(1).ToList();

                foreach (var rightside in Enumerate(unused, k - 1, withRepetition))
                {
                    yield return leftside.Concat(rightside).ToArray();
                }
            }
        }
    }

    class MainClass
    {
        public static void Main(string[] args)
        {
            //引数の処理
            var strPointNum = Console.ReadLine();

            int pointNum = 0;
            if (!int.TryParse(strPointNum, out pointNum)) return;

            var list = new List<Point>();
            for(int i=0;i<pointNum;i++)
            {
                var strPoint = Console.ReadLine().Split(' ');

                list.Add(new Point(Convert.ToInt32(strPoint[0]), Convert.ToInt32(strPoint[1])));
            }

            if(list.Count < 3)
            {
                //点が３つ以上ないときは何もできないので、0を返す
                Console.WriteLine("0");
                return;
            }


            //追加した点の個数
            var countMax = 0;

            IEnumerable<int[]> patternPrev = new List<int[]>();

            while(true)
            {
                //前回分の組み合わせのパターン
                var range = Enumerable.Range(0, list.Count()).ToArray();
                var pattern = Combination.Enumerate(range, 3, withRepetition: false);

                //前回分のパターンを無視
                pattern = pattern.Where(x => !patternPrev.Where(y => y.SequenceEqual(x)).Any()).ToList();

                if (pattern.Count() <= 0) break;

                //追加する点用のリスト
                var listAdd = new List<Point>();

                foreach (var n in pattern)
                {

                
                    var p1 = list.ElementAt(n[0]);
                    var p2 = list.ElementAt(n[1]);
                    var p3 = list.ElementAt(n[2]);

                    //新しい点を作成
                    Point p4 = null;

                    if(p1.X == p2.X)
                    {
                        if(p1.Y == p3.Y)
                        {
                            p4 = new Point(p3.X, p2.Y);
                        }
                        else if(p2.Y == p3.Y)
                        {
                            p4 = new Point(p3.X, p1.Y);
                        }
                    }
                    else if(p1.X == p3.X)
                    {
                        if (p1.Y == p2.Y)
                        {
                            p4 = new Point(p2.X, p3.Y);
                        }
                        else if (p2.Y == p3.Y)
                        {
                            p4 = new Point(p2.X, p1.Y);
                        }
                    }
                    else if(p2.X == p3.X)
                    {
                        if (p2.Y == p1.Y)
                        {
                            p4 = new Point(p1.X, p3.Y);
                        }
                        else if (p3.Y == p1.Y)
                        {
                            p4 = new Point(p1.X, p2.Y);
                        }
                    }

                    if (p4 == null) continue;
                    

                    //まだ追加していない点なら追加
                    if(!list.Contains(p4) && !listAdd.Contains(p4))
                    {
                        listAdd.Add(p4);
                    }
                }

                if (listAdd.Count <= 0) break;

                countMax += listAdd.Count;

                //次回のループの準備
                list.AddRange(listAdd);
                listAdd.Clear();
                patternPrev = pattern.ToList();
            }

            //答え表示
            Console.WriteLine(Convert.ToString(countMax));

        }
    }
}