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++ (GCC 9.2.1) (judge verdict: Accepted)

#include "bits/stdc++.h"
using namespace std;
#define int long long
#define FOR(i, a, b) for(int i=(a);i<(b);i++)
#define RFOR(i, a, b) for(int i=(b-1);i>=(a);i--)
#define REP(i, n) for(int i=0; i<(n); i++)
#define RREP(i, n) for(int i=(n-1); i>=0; i--)
#define REP1(i, n) for(int i=1; i<=(n); i++)
#define RREP1(i, n) for(int i=(n); i>=1; i--)
#define ALL(a) (a).begin(),(a).end()
#define UNIQUE_SORT(l) sort(ALL(l)); l.erase(unique(ALL(l)), l.end());
#define CONTAIN(a, b) find(ALL(a), (b)) != (a).end()
#define out(...) printf(__VA_ARGS__)
#if DEBUG
#define debug(...) printf(__VA_ARGS__)
#else
#define debug(...) /* ... */
#endif
template<class T>bool chmax(T &a,const T &b){if(a<b){a=b;return true;}return false;}
template<class T>bool chmin(T &a,const T &b){if(b<a){a=b;return true;}return false;}
void _OUT() {}; template<class H, class... T> void _OUT(H &h, T &... t) { cout<<' '<<h; _OUT(t...); };
template<class H, class... T> void _P(H &h, T &... t) { cout<<h; _OUT(t...); };
#define _PN(...) _P(__VA_ARGS__); cout << endl;
#define EXEC(...) void exec() { (__VA_ARGS__ - 1) ? multi() : solve(0); }

void exec();
void solve(int t);
void multi() { int TT; cin>>TT; REP1(t,TT) solve(t); }
signed main()
{
#if DEBUG
    std::ifstream in("input.txt");
    std::cin.rdbuf(in.rdbuf());
#endif
    cin.tie(0);
    ios::sync_with_stdio(false);
    exec();
    return 0;
}

/*================================*/
#if DEBUG
#define SIZE 123450
#else
#define SIZE 123450
#endif

int N,M;
vector<int> A(SIZE);

struct UnionFind {
    vector<int> parent;
    int size;
    vector<set<int>> V;
    UnionFind(int size) {
        reset(size);
    }
    void reset(int size) {
        this->size = size;
        parent.resize(size);
        REP(i,size) parent[i]=i;
        V.resize(size);
        REP(i,size) V[i].insert(i);
    }
    int root(int i) {
        if (parent[i] == i) return i;
        return parent[i] = root(parent[i]);
    }
    void merge(int i, int j) {
        int ir = root(i);
        int jr = root(j);
        if (ir == jr) return;
        int next = (V[ir].size() >= V[jr].size()) ? ir : jr;
        int hide = (ir == next) ? jr : ir;
        parent[ir] = parent[jr] = next;
        for (int n:V[hide]) V[next].insert(n);
        V[hide].clear();
    }
    bool same(int i, int j) {
        return root(i) == root(j);
    }
    int vsize(int i) {
        return (int)V[i].size();
    }
};


void solve(int _t) {
    cin>>N;
    auto uf = new UnionFind(SIZE);
    int x,y;
    set<int> ylist[SIZE];
    vector<pair<int,int>> V;
    REP(i,N) {
        cin>>x>>y;
        ylist[x].insert(y);
        V.push_back({x,y});
    }
    REP(i,SIZE)if(ylist[i].size()) {
        int y0 = *ylist[i].begin();
        for (int y:ylist[i]) {
            uf->merge(y0, y);
        }
    }
    vector<set<int>> xlist(SIZE);
    for (auto p:V) {
        xlist[uf->root(p.second)].insert(p.first);
        debug("xlist[%lld].insert(%lld)\n",uf->root(p.second),p.first);
    }
    int ans = -N;
    REP(i,SIZE) {
        ans += xlist[i].size() * uf->vsize(i);
    }
    _PN(ans);
}
EXEC(1)