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 Rust (1.15.1) (judge verdict: Accepted)

#[allow(unused_macros)]
macro_rules! parse_line {
    ( $t:ty ) => (
        {
            let mut line = String::new();
            ::std::io::stdin().read_line(&mut line).unwrap();
            let mut iter = line.split_whitespace();
            iter.next().unwrap().parse::<$t>().unwrap()
        }
    );

    ( $( $t:ty), +) => (
        {
            let mut line = String::new();
            ::std::io::stdin().read_line(&mut line).unwrap();
            let mut iter = line.split_whitespace();
            ( $(iter.next().unwrap().parse::<$t>().unwrap()),* )
        }
    );
}

#[allow(unused_macros)]
macro_rules! read_line {
    () => {{
        let mut line = String::new();
        ::std::io::stdin().read_line(&mut line).unwrap();
        line.pop();
        line
    }};
}

#[allow(unused_macros)]
macro_rules! parse_vec {
    ( $t:ty ) => {{
        let mut line = String::new();
        ::std::io::stdin().read_line(&mut line).unwrap();
        let iter = line.split_whitespace();
        iter.map(|v| v.parse::<$t>().unwrap()).collect::<Vec<_>>()
    }};
}

use std::cell::RefCell;
use std::rc::Rc;

struct UnionFind {
    par: Rc<RefCell<Vec<usize>>>,
}

impl UnionFind {
    fn new(n: usize) -> Self {
        let uf = UnionFind {
            par: Rc::new(RefCell::new(vec![0; n])),
        };
        for i in 0..n {
            uf.par.borrow_mut()[i] = i;
        }
        uf
    }

    fn root(&self, x: usize) -> usize {
        let t = self.par.borrow()[x];
        if t == x {
            x
        } else {
            self.par.borrow_mut()[x] = self.root(t);
            self.par.borrow()[x]
        }
    }

    fn same(&self, x: usize, y: usize) -> bool {
        self.root(x) == self.root(y)
    }

    fn unite(&self, mut x: usize, mut y: usize) {
        x = self.root(x);
        y = self.root(y);
        if x == y {
            return;
        }

        self.par.borrow_mut()[x] = y;
    }
}

fn solve(xys: &[(usize, usize)]) -> usize {
    let n = xys.len();
    const MAX: usize = 110000;

    let uf = UnionFind::new(MAX * 2 + 1);

    let mut mx = vec![0; MAX * 2 + 1];
    let mut my = vec![0; MAX * 2 + 1];

    for &(x, y) in xys.iter() {
        uf.unite(x, y + MAX);
    }

    for i in 1..(MAX + 1) {
        mx[uf.root(i)] += 1;
        my[uf.root(i + MAX)] += 1;
    }

    let mut ans = 0;

    for i in 1..(MAX * 2 + 1) {
        ans += mx[i] * my[i];
    }

    ans - n
}

fn main() {
    let n = parse_line!(usize);
    let xys = (0..n)
        .map(|_| parse_line!(usize, usize))
        .collect::<Vec<_>>();
    println!("{}", solve(&xys));
}

#[test]
fn solve_test() {
    assert_eq!(solve(&[(1, 1), (5, 1), (5, 5)]), 1);
    assert_eq!(solve(&[(10, 10), (20, 20)]), 0);
}