#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <utility>
#include <string>
#include <algorithm>
#include <map>
#include <vector>
#include <climits>
#include <numeric>
#include<stdio.h>
#include <queue>
#include <iomanip>
#include <float.h>
#include <set>
#include<functional>
#include <stack>
#include <time.h>
#include <climits>
#include <bitset>
#include <fstream>
#include<map>
using namespace std;
long long gcd(long long a, long long b) {
	if (b == 0) return a;
	return gcd(b, a % b);
}
vector<long long> divisor(long long n) {
	vector< long long> ret;
	for (long long i = 1; i * i <= n; i++) {
		if (n % i == 0) {
			ret.push_back(i);
			if (i * i != n) ret.push_back(n / i);
		}
	}
	sort(begin(ret), end(ret));
	return (ret);
}
struct LazySegmentTree {
private:
	int n;
	vector<int> node, lazy;
	vector<bool> lazyFlag;

public:
	LazySegmentTree(vector<int> v) {
		int sz = (int)v.size();
		n = 1; while (n < sz) n *= 2;
		node.resize(2 * n - 1);
		lazy.resize(2 * n - 1, INT_MAX);
		lazyFlag.resize(2 * n - 1, false);

		for (int i = 0; i<sz; i++) node[i + n - 1] = v[i];
		for (int i = n - 2; i >= 0; i--) node[i] = min(node[i * 2 + 1], node[i * 2 + 2]);
	}

	void lazyEvaluate(int k, int l, int r) {
		if (lazyFlag[k]) {
			node[k] = lazy[k];
			if (r - l > 1) {
				lazy[k * 2 + 1] = lazy[k * 2 + 2] = lazy[k];
				lazyFlag[k * 2 + 1] = lazyFlag[k * 2 + 2] = true;
			}
			lazyFlag[k] = false;
		}
	}

	void update(int a, int b, int x, int k = 0, int l = 0, int r = -1) {
		if (r < 0) r = n;
		lazyEvaluate(k, l, r);
		if (b <= l || r <= a) return;
		if (a <= l && r <= b) {
			lazy[k] = x;
			lazyFlag[k] = true;
			lazyEvaluate(k, l, r);
		}
		else {
			update(a, b, x, 2 * k + 1, l, (l + r) / 2);
			update(a, b, x, 2 * k + 2, (l + r) / 2, r);
			node[k] = min(node[2 * k + 1], node[2 * k + 2]);
		}
	}

	int find(int a, int b, int k = 0, int l = 0, int r = -1) {
		if (r < 0) r = n;
		lazyEvaluate(k, l, r);
		if (b <= l || r <= a) return INT_MAX;
		if (a <= l && r <= b) return node[k];
		int vl = find(a, b, 2 * k + 1, l, (l + r) / 2);
		int vr = find(a, b, 2 * k + 2, (l + r) / 2, r);
		return min(vl, vr);
	}
};
#define ll long long
class UnionFind {
public:
	vector <ll> par; // 各元の親を表す配列
	vector <ll> siz; // 素集合のサイズを表す配列(1 で初期化)

					 // Constructor
	UnionFind(ll sz_) : par(sz_), siz(sz_, 1LL) {
		for (ll i = 0; i < sz_; ++i) par[i] = i; // 初期では親は自分自身
	}
	void init(ll sz_) {
		par.resize(sz_);
		siz.assign(sz_, 1LL);  // resize だとなぜか初期化されなかった
		for (ll i = 0; i < sz_; ++i) par[i] = i; // 初期では親は自分自身
	}

	// Member Function
	// Find
	ll root(ll x) { // 根の検索
		while (par[x] != x) {
			x = par[x] = par[par[x]]; // x の親の親を x の親とする
		}
		return x;
	}

	// Union(Unite, Merge)
	bool merge(ll x, ll y) {
		x = root(x);
		y = root(y);
		if (x == y) return false;
		// merge technique（データ構造をマージするテク．小を大にくっつける）
		if (siz[x] < siz[y]) swap(x, y);
		siz[x] += siz[y];
		par[y] = x;
		return true;
	}

	bool issame(ll x, ll y) { // 連結判定
		return root(x) == root(y);
	}

	ll size(ll x) { // 素集合のサイズ
		return siz[root(x)];
	}
};
typedef pair<long long, long long>p;
long long mod = 1000000007;
long long calc(long long k) {
	return k*(k + 1) / 2;
}
class BIT
{
public:
	vector<int> bit;
	int M;

	BIT(int M) :
		bit(vector<int>(M + 1, 0)), M(M) {}

	int sum(int i) {
		if (!i) return 0;
		if (i == 0)return 0;
		return bit[i] + sum(i - (i&-i));
	}

	void add(int i, int x) {
		if (i > M) return;
		bit[i] += x;
		add(i + (i&-i), x);
	}
};
signed main()
{
	cin.tie(0);
	ios::sync_with_stdio(false);
	cout << fixed << setprecision(16);
	int n;
	cin >> n;
	map<long long, long long>ma;
	p point[200004];//y,x
	vector<int>xs;
	for (int i = 0; i < n; i++) {
		cin >> point[i].second >> point[i].first;
		xs.push_back(point[i].second);
	}
	sort(point, point + n);
	sort(xs.begin(), xs.end());
	map<long long, long long>ma2;//x座標が何番目か
	int tt = 1;
	for (int i = 0; i < n; i++) {
		if (ma2.find(xs[i]) == ma2.end()) {
			ma2[xs[i]] = tt++;
		}
	}
	long long ans = 0;
	long long cnt = 0;
	int now = n - 1;
	BIT bi(n);
	while (1) {
		if (now == -1)break;
		vector<int>ne;
		int index = ma2[point[now].second];
		ans -= calc(bi.sum(n) - bi.sum(index));
		int xxx = bi.sum(n) - bi.sum(index);

		if (ma.find(point[now].second) == ma.end()) { cnt += 1; ma[point[now].second] = 1; ne.push_back(point[now].second); }
		while (now - 1 >= 0 && point[now].first == point[now - 1].first) {
			now -= 1;
			if (ma.find(point[now].second) == ma.end()) {
				cnt += 1; ma[point[now].second] = 1; ne.push_back(point[now].second);
			}
			int index2 = ma2[point[now].second];
			if (index - 1 > index2) {
				ans -= calc(bi.sum(index - 1) - bi.sum(index2));
				int kkk = calc(bi.sum(index - 1) - bi.sum(index2));
				int x = 0;
			}
			index = index2;
		}
		ans -= calc(bi.sum(index - 1));
		ans += calc(cnt);
		for (int i = 0; i < ne.size(); i++) {
			bi.add(ma2[ne[i]], 1);
		}
		now -= 1;
	}
	cout << ans;
}


#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <utility>
#include <string>
#include <algorithm>
#include <map>
#include <vector>
#include <climits>
#include <numeric>
#include<stdio.h>
#include <queue>
#include <iomanip>
#include <float.h>
#include <set>
#include<functional>
#include <stack>
#include <time.h>
#include <climits>
#include <bitset>
#include <fstream>
#include<map>
using namespace std;
long long gcd(long long a, long long b) {
	if (b == 0) return a;
	return gcd(b, a % b);
}
vector<long long> divisor(long long n) {
	vector< long long> ret;
	for (long long i = 1; i * i <= n; i++) {
		if (n % i == 0) {
			ret.push_back(i);
			if (i * i != n) ret.push_back(n / i);
		}
	}
	sort(begin(ret), end(ret));
	return (ret);
}
struct LazySegmentTree {
private:
	int n;
	vector<int> node, lazy;
	vector<bool> lazyFlag;

public:
	LazySegmentTree(vector<int> v) {
		int sz = (int)v.size();
		n = 1; while (n < sz) n *= 2;
		node.resize(2 * n - 1);
		lazy.resize(2 * n - 1, INT_MAX);
		lazyFlag.resize(2 * n - 1, false);

		for (int i = 0; i<sz; i++) node[i + n - 1] = v[i];
		for (int i = n - 2; i >= 0; i--) node[i] = min(node[i * 2 + 1], node[i * 2 + 2]);
	}

	void lazyEvaluate(int k, int l, int r) {
		if (lazyFlag[k]) {
			node[k] = lazy[k];
			if (r - l > 1) {
				lazy[k * 2 + 1] = lazy[k * 2 + 2] = lazy[k];
				lazyFlag[k * 2 + 1] = lazyFlag[k * 2 + 2] = true;
			}
			lazyFlag[k] = false;
		}
	}

	void update(int a, int b, int x, int k = 0, int l = 0, int r = -1) {
		if (r < 0) r = n;
		lazyEvaluate(k, l, r);
		if (b <= l || r <= a) return;
		if (a <= l && r <= b) {
			lazy[k] = x;
			lazyFlag[k] = true;
			lazyEvaluate(k, l, r);
		}
		else {
			update(a, b, x, 2 * k + 1, l, (l + r) / 2);
			update(a, b, x, 2 * k + 2, (l + r) / 2, r);
			node[k] = min(node[2 * k + 1], node[2 * k + 2]);
		}
	}

	int find(int a, int b, int k = 0, int l = 0, int r = -1) {
		if (r < 0) r = n;
		lazyEvaluate(k, l, r);
		if (b <= l || r <= a) return INT_MAX;
		if (a <= l && r <= b) return node[k];
		int vl = find(a, b, 2 * k + 1, l, (l + r) / 2);
		int vr = find(a, b, 2 * k + 2, (l + r) / 2, r);
		return min(vl, vr);
	}
};
#define ll long long
class UnionFind {
public:
	vector <ll> par; // 各元の親を表す配列
	vector <ll> siz; // 素集合のサイズを表す配列(1 で初期化)

					 // Constructor
	UnionFind(ll sz_) : par(sz_), siz(sz_, 1LL) {
		for (ll i = 0; i < sz_; ++i) par[i] = i; // 初期では親は自分自身
	}
	void init(ll sz_) {
		par.resize(sz_);
		siz.assign(sz_, 1LL);  // resize だとなぜか初期化されなかった
		for (ll i = 0; i < sz_; ++i) par[i] = i; // 初期では親は自分自身
	}

	// Member Function
	// Find
	ll root(ll x) { // 根の検索
		while (par[x] != x) {
			x = par[x] = par[par[x]]; // x の親の親を x の親とする
		}
		return x;
	}

	// Union(Unite, Merge)
	bool merge(ll x, ll y) {
		x = root(x);
		y = root(y);
		if (x == y) return false;
		// merge technique（データ構造をマージするテク．小を大にくっつける）
		if (siz[x] < siz[y]) swap(x, y);
		siz[x] += siz[y];
		par[y] = x;
		return true;
	}

	bool issame(ll x, ll y) { // 連結判定
		return root(x) == root(y);
	}

	ll size(ll x) { // 素集合のサイズ
		return siz[root(x)];
	}
};
typedef pair<long long,long long>p;
long long mod = 1000000007;
long long calc(long long k) {
	return k*(k + 1) / 2;
}
class BIT
{
public:
	vector<int> bit;
	int M;

	BIT(int M) :
		bit(vector<int>(M + 1, 0)), M(M) {}

	int sum(int i) {
		if (!i) return 0;
		if (i == 0)return 0;
		return bit[i] + sum(i - (i&-i));
	}

	void add(int i, int x) {
		if (i > M) return;
		bit[i] += x;
		add(i + (i&-i), x);
	}
};
signed main()
{
	cin.tie(0);
	ios::sync_with_stdio(false);
	cout << fixed << setprecision(16);
	int n;
	cin >> n;
	map<long long,long long>ma;
	p point[200004];//y,x
	vector<int>xs;
	for (int i = 0; i < n; i++) {
		cin >> point[i].second >> point[i].first;
		xs.push_back(point[i].second);
	}
	sort(point, point + n);
	sort(xs.begin(), xs.end());
	map<long long, long long>ma2;//x座標が何番目か
	int tt = 1;
	for (int i = 0; i < n; i++) {
		if (ma2.find(xs[i]) == ma2.end()) {
			ma2[xs[i]] = tt++;
		}
	}
	long long ans = 0;
	long long cnt = 0;
	int now = n-1;
	BIT bi(n);
	while (1) {
		if (now == -1)break;
		vector<int>ne;
		int index = ma2[point[now].second];
		ans -= calc(bi.sum(n)-bi.sum(index));
		if (ma.find(point[now].second) == ma.end()) { cnt += 1; ma[point[now].second] = 1; ne.push_back(point[now].second); }
		while (now -1>=0&&point[now].first == point[now - 1].first) {
			now -= 1;
			if (ma.find(point[now].second) == ma.end()) {
				cnt += 1; ma[point[now].second] = 1; ne.push_back(point[now].second);
			}
			int index2 = ma2[point[now].second];
			if (index-1 > index2+1) {
				ans -= calc(bi.sum(index - 1) - bi.sum(index2 + 1));
			}
			index = index2;
		}
		ans -= calc(bi.sum(index - 1));
		ans+=calc(cnt);
		for (int i = 0; i < ne.size(); i++) {
			bi.add(ma2[point[now].second], 1);
		}
		now -= 1;
	}
	cout << ans;
}


#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <utility>
#include <string>
#include <algorithm>
#include <map>
#include <vector>
#include <climits>
#include <numeric>
#include<stdio.h>
#include <queue>
#include <iomanip>
#include <float.h>
#include <set>
#include<functional>
#include <stack>
#include <time.h>
#include <climits>
#include <bitset>
#include <fstream>
#include<map>
using namespace std;
long long gcd(long long a, long long b) {
	if (b == 0) return a;
	return gcd(b, a % b);
}
vector<long long> divisor(long long n) {
	vector< long long> ret;
	for (long long i = 1; i * i <= n; i++) {
		if (n % i == 0) {
			ret.push_back(i);
			if (i * i != n) ret.push_back(n / i);
		}
	}
	sort(begin(ret), end(ret));
	return (ret);
}
struct LazySegmentTree {
private:
	int n;
	vector<int> node, lazy;
	vector<bool> lazyFlag;

public:
	LazySegmentTree(vector<int> v) {
		int sz = (int)v.size();
		n = 1; while (n < sz) n *= 2;
		node.resize(2 * n - 1);
		lazy.resize(2 * n - 1, INT_MAX);
		lazyFlag.resize(2 * n - 1, false);

		for (int i = 0; i<sz; i++) node[i + n - 1] = v[i];
		for (int i = n - 2; i >= 0; i--) node[i] = min(node[i * 2 + 1], node[i * 2 + 2]);
	}

	void lazyEvaluate(int k, int l, int r) {
		if (lazyFlag[k]) {
			node[k] = lazy[k];
			if (r - l > 1) {
				lazy[k * 2 + 1] = lazy[k * 2 + 2] = lazy[k];
				lazyFlag[k * 2 + 1] = lazyFlag[k * 2 + 2] = true;
			}
			lazyFlag[k] = false;
		}
	}

	void update(int a, int b, int x, int k = 0, int l = 0, int r = -1) {
		if (r < 0) r = n;
		lazyEvaluate(k, l, r);
		if (b <= l || r <= a) return;
		if (a <= l && r <= b) {
			lazy[k] = x;
			lazyFlag[k] = true;
			lazyEvaluate(k, l, r);
		}
		else {
			update(a, b, x, 2 * k + 1, l, (l + r) / 2);
			update(a, b, x, 2 * k + 2, (l + r) / 2, r);
			node[k] = min(node[2 * k + 1], node[2 * k + 2]);
		}
	}

	int find(int a, int b, int k = 0, int l = 0, int r = -1) {
		if (r < 0) r = n;
		lazyEvaluate(k, l, r);
		if (b <= l || r <= a) return INT_MAX;
		if (a <= l && r <= b) return node[k];
		int vl = find(a, b, 2 * k + 1, l, (l + r) / 2);
		int vr = find(a, b, 2 * k + 2, (l + r) / 2, r);
		return min(vl, vr);
	}
};
#define ll long long
class UnionFind {
public:
	vector <ll> par; // 各元の親を表す配列
	vector <ll> siz; // 素集合のサイズを表す配列(1 で初期化)

					 // Constructor
	UnionFind(ll sz_) : par(sz_), siz(sz_, 1LL) {
		for (ll i = 0; i < sz_; ++i) par[i] = i; // 初期では親は自分自身
	}
	void init(ll sz_) {
		par.resize(sz_);
		siz.assign(sz_, 1LL);  // resize だとなぜか初期化されなかった
		for (ll i = 0; i < sz_; ++i) par[i] = i; // 初期では親は自分自身
	}

	// Member Function
	// Find
	ll root(ll x) { // 根の検索
		while (par[x] != x) {
			x = par[x] = par[par[x]]; // x の親の親を x の親とする
		}
		return x;
	}

	// Union(Unite, Merge)
	bool merge(ll x, ll y) {
		x = root(x);
		y = root(y);
		if (x == y) return false;
		// merge technique（データ構造をマージするテク．小を大にくっつける）
		if (siz[x] < siz[y]) swap(x, y);
		siz[x] += siz[y];
		par[y] = x;
		return true;
	}

	bool issame(ll x, ll y) { // 連結判定
		return root(x) == root(y);
	}

	ll size(ll x) { // 素集合のサイズ
		return siz[root(x)];
	}
};
typedef pair<int,int>p;
long long mod = 1000000007;
long long calc(long long k) {
	return k*(k + 1) / 2;
}
signed main()
{
	cin.tie(0);
	ios::sync_with_stdio(false);
	cout << fixed << setprecision(16);
	int n;
	cin >> n;
	map<int, int>ma;
	p point[200004];
	long long cnt = 0;
	for (int i = 0; i < n; i++) {
		cin >> point[i].second >> point[i].first;//y,x
		if (ma.find(point[i].second) == ma.end()) { ma[point[i].second] = 1; cnt += 1; }
		else ma[point[i].second] += 1;
	}
	sort(point, point + n);
	long long ans = 0;
	ans += calc(cnt);
	int now = 0;
	while (1) {
		if (now == n)break;
		while (now + 1<=n-1&&point[now].first == point[now + 1].first) {
			ma[point[now].second] -= 1;
			if (ma[point[now].second] == 0)cnt -= 1;
			now += 1;
		}
		if (now != n) {
			ma[point[now].second] -= 1;
			if (ma[point[now].second] == 0)cnt -= 1;
			now += 1;
			ans += calc(cnt);
		}
	}
	cout << ans;
}


#include<bits/stdc++.h>

using namespace std;

#define ll  long long
#define X   first
#define Y   second

#define all(x)  x.begin(),x.end()
#define sz(x)   (int)x.size()

#define pb      emplace_back
#define endl    "\n"

const ll    inf = 1e18;
const int   N   = 2e5 + 5;

typedef pair<int,int>   ii;

namespace BIT2D {
    vector<int> val[N];
    vector<int> bit[N];

    void ini()  {
        for(int i = 1 ; i < N ; ++i)    {
            sort(all(val[i]));
            val[i].resize(unique(all(val[i])) - val[i].begin());
            bit[i].resize(sz(val[i]) + 5);
        }
    }
    void add(int x,int y)   {
        for(; x < N ; x += x & -x)
            val[x].pb(y);
    }
    int upd(int x,int y)    {
        for(; x < N ; x += x & -x)  {
            int p = upper_bound(all(val[x]),y) - val[x].begin();
            for(; p > 0 ; p -= p & -p)
                bit[x][p]++;
        }
    }
    int get(int x,int y)    {
        int ans = 0;
        for(; x > 0 ; x -= x & -x)  {
            int p = lower_bound(all(val[x]),y) - val[x].begin() + 1;    assert(p > 0);
            for(; p <  bit[x].size() ; p += p & -p)
                ans += bit[x][p];
        }
        return  ans;
    }
}

int main()  {
    ios_base::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);

    int n;  cin >> n;

    vector<ii>  P(n);
    vector<int> row;
    vector<int> col;

    for(ii &e : P)
        cin >> e.X >> e.Y,
        row.pb(e.X),
        col.pb(e.Y);

    sort(all(row));
    sort(all(col));
    sort(all(P),[&](ii &a,ii &b)    {
        if (a.X != b.X)
            return  a.X < b.X;
        else
            return  a.Y > b.Y;
    });

    for(ii &e : P)  {
        e.X = upper_bound(all(row),e.X) - row.begin();
        e.Y = upper_bound(all(col),e.Y) - col.begin();

        BIT2D::add(e.X,e.Y);
    }

    BIT2D::ini();

    ll  ans = 0;

    for(int i = 0 ; i < n ;)    {
        int j = i;

        BIT2D::upd(P[i].X,P[i].Y);

        while(j < n && P[j].X == P[i].X)
            ans += 1ll * BIT2D::get(n,P[j].Y),
            j++;

        i = j;
    }

    cout << ans << endl;
}


#include<bits/stdc++.h>

using namespace std;

#define ll  long long
#define X   first
#define Y   second

#define all(x)  x.begin(),x.end()
#define sz(x)   (int)x.size()

#define pb      emplace_back
#define endl    "\n"

const ll    inf = 1e18;
const int   N   = 2e5 + 5;

typedef pair<int,int>   ii;

int t[N];

int main()  {
    ios_base::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);

    int n;  cin >> n;

    auto upd = [&](int p)   {
        for(; p < N ; p += p & -p)
            t[p]++;
    };
    auto get = [&](int l,int r) {   --l;
        int ans = 0;

        for(; l > 0 ; l -= l & -l)  ans -= t[l];
        for(; r > 0 ; r -= r & -r)  ans += t[r];

        return  ans;
    };

    vector<ii>  P(n);
    vector<int> row;

    for(ii &e : P)
        cin >> e.Y >> e.X,
        row.pb(e.Y);

    sort(all(row)); row.erase(unique(all(row)),row.end());

    sort(all(P),greater<ii>());

    for(ii &e : P)  e.Y = upper_bound(all(row),e.Y) - row.begin();

    ll  ans = 0;

    for(int i = 0 ; i < n ;)    {
        int j = i;

        vector<int> col = {0,n + 1};

        while (j < n && P[j].X == P[i].X)
            col.pb(P[j++].Y);

        sort(all(col));

        for(int j = 1 ; j < sz(col) ; ++j)  {
            int x = get(col[j - 1] + 1,col[j] - 1);
            if (x < 0)
                x = 0;
            ans -= 1ll * x * (x + 1) / 2;
        }

        while(i < j)    {
            if(!get(P[i].Y,P[i].Y))
                upd(P[i].Y);
            i++;
        }

        int x = get(1,n);

        ans += 1ll * x * (x + 1) / 2;
    }

    cout << ans << endl;
}
/*
5
3 6
5 10
4 3
2 1
1 3
*/


#include<bits/stdc++.h>

using namespace std;

#define ll  long long
#define X   first
#define Y   second

#define all(x)  x.begin(),x.end()
#define sz(x)   (int)x.size()

#define pb      emplace_back
#define endl    "\n"

const ll    inf = 1e18;
const int   N   = 2e5 + 5;

typedef pair<int,int>   ii;

int main()  {
    ios_base::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);

    int n;  cin >> n;

    vector<ii>  P(n);

    for(ii &e : P)
        cin >> e.X >> e.Y;

    sort(P.begin(),P.end());

    set<int> row;
    set<int> col;

    ll  ans = 0;

    for(int i = 0 ; i < n ;)    {
        int j = i;

        while(j < n && P[j].X == P[i].X)    {
            row.insert(P[j].X);
            col.insert(P[j].Y);
            j++;
        }
        i = j;

        ans += 1ll * sz(row) * sz(col);
    }

    cout << ans << endl;
}


#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#define pb push_back

typedef long long LL;

const int N=200005;

int n,b[N],t[N],c[N];
struct data{int x,y;}a[N];
std::vector<int> vec[N];
bool vis[N];

bool cmp(data a,data b)
{
	return a.y<b.y||a.y==b.y&&a.x<b.x;
}

LL get(int x)
{
	return (LL)x*(x+1)/2;
}

void ins(int x,int y)
{
	while (x<=n) c[x]+=y,x+=x&(-x);
}

int find(int x)
{
	int ans=0;
	while (x) ans+=c[x],x-=x&(-x);
	return ans;
}

int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y);
	std::sort(a+1,a+n+1,cmp);
	for (int i=1;i<=n;i++) t[i]=a[i].x;
	std::sort(t+1,t+n+1);
	for (int i=1;i<=n;i++) a[i].x=std::lower_bound(t+1,t+n+1,a[i].x)-t;
	for (int i=1;i<=n;i++) t[i]=a[i].y;
	std::sort(t+1,t+n+1);
	for (int i=1;i<=n;i++) a[i].y=std::lower_bound(t+1,t+n+1,a[i].y)-t;
	for (int i=1;i<=n;i++) vec[a[i].y].pb(a[i].x);
	LL ans=0;
	for (int i=n;i>=1;i--)
	{
		if (!vec[i].size()) continue;
		int tot=0;
		for (int j=0;j<vec[i].size();j++) b[++tot]=vec[i][j];
		for (int j=1;j<=tot;j++) if (!vis[b[j]]) vis[b[j]]=1,ins(b[j],1);
		ans+=get(find(n));
		ans-=get(find(b[1]-1));
		ans-=get(find(n)-find(b[tot]));
		for (int j=1;j<tot;j++) ans-=get(find(b[j+1]-1)-find(b[j]));
	}
	printf("%lld\n",ans);
	return 0;
}


#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#define pb push_back

typedef long long LL;

const int N=200005;

int n,b[N],t[N],c[N];
struct data{int x,y;}a[N];
std::vector<int> vec[N];
bool vis[N];

bool cmp(data a,data b)
{
	return a.y<b.y||a.y==b.y&&a.x<b.x;
}

LL get(int x)
{
	return (LL)x*(x+1)/2;
}

void ins(int x,int y)
{
	while (x<=n) c[x]+=y,x+=x&(-x);
}

int find(int x)
{
	int ans=0;
	while (x) ans+=c[x],x-=x&(-x);
	return ans;
}

int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y);
	for (int i=1;i<=n;i++) t[i]=a[i].x;
	std::sort(t+1,t+n+1);
	for (int i=1;i<=n;i++) a[i].x=std::lower_bound(t+1,t+n+1,a[i].x)-t;
	for (int i=1;i<=n;i++) t[i]=a[i].y;
	std::sort(t+1,t+n+1);
	for (int i=1;i<=n;i++) a[i].y=std::lower_bound(t+1,t+n+1,a[i].y)-t;
	for (int i=1;i<=n;i++) vec[a[i].y].pb(a[i].x);
	LL ans=0;
	for (int i=n;i>=1;i--)
	{
		if (!vec[i].size()) continue;
		int tot=0;
		for (int j=0;j<vec[i].size();j++) b[++tot]=vec[i][j];
		for (int j=1;j<=tot;j++) if (!vis[b[j]]) vis[b[j]]=1,ins(b[j],1);
		ans+=get(find(n));
		ans-=get(find(b[1]-1));
		ans-=get(find(n)-find(b[tot]));
		for (int j=1;j<tot;j++) ans-=get(find(b[j+1]-1)-find(b[j]));
	}
	printf("%lld\n",ans);
	return 0;
}


#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#define pb push_back

typedef long long LL;

const int N=200005;

int n,b[N],ls[N],t[N];
struct data{int x,y;}a[N];
std::vector<int> vec[N];

bool cmp(data a,data b)
{
	return a.x<b.x;
}

int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y);
	for (int i=1;i<=n;i++) t[i]=a[i].x;
	std::sort(t+1,t+n+1);
	for (int i=1;i<=n;i++) a[i].x=std::lower_bound(t+1,t+n+1,a[i].x)-t;
	for (int i=1;i<=n;i++) t[i]=a[i].y;
	std::sort(t+1,t+n+1);
	for (int i=1;i<=n;i++) a[i].y=std::lower_bound(t+1,t+n+1,a[i].y)-t;
	int m=0;
	for (int i=1;i<=n;i++)
		if (!m||a[i].x!=b[m]) b[++m]=a[i].x,vec[m].pb(a[i].y);
		else vec[m].pb(a[i].y);
	LL now=0,ans=0;
	for (int i=1;i<=m;i++)
	{
		for (int j=0;j<vec[i].size();j++) now+=i-ls[vec[i][j]],ls[vec[i][j]]=i;
		ans+=now;
	}
	printf("%lld\n",ans);
	return 0;
}


#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#define pb push_back

typedef long long LL;

const int N=200005;

int n,b[N],ls[N],t[N];
struct data{int x,y;}a[N];
std::vector<int> vec[N];
LL c[N];

bool cmp(data a,data b)
{
	return a.x<b.x||a.x==b.x&&a.y<b.y;
}

void ins(int x,LL y)
{
	while (x<=n) c[x]+=y,x+=x&(-x);
}

LL find(int x)
{
	LL ans=0;
	while (x) ans+=c[x],x-=x&(-x);
	return ans;
}

int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y);
	for (int i=1;i<=n;i++) t[i]=a[i].x;
	std::sort(t+1,t+n+1);
	for (int i=1;i<=n;i++) a[i].x=std::lower_bound(t+1,t+n+1,a[i].x)-t;
	for (int i=1;i<=n;i++) t[i]=a[i].y;
	std::sort(t+1,t+n+1);
	for (int i=1;i<=n;i++) a[i].y=std::lower_bound(t+1,t+n+1,a[i].y)-t;
	int m=0;
	for (int i=1;i<=n;i++)
		if (!m||a[i].x!=b[m]) b[++m]=a[i].x,vec[m].pb(a[i].y);
		else vec[m].pb(a[i].y);
	LL ans=0;
	for (int i=1;i<=m;i++)
	{
		for (int j=0;j<vec[i].size();j++) ins(vec[i][j],i-ls[vec[i][j]]),ls[vec[i][j]]=i;
		ans+=find(vec[i][vec[i].size()-1]);
	}
	printf("%lld\n",ans);
	return 0;
}


#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#define pb push_back

typedef long long LL;

const int N=200005;

int n,b[N],t[N];
struct data{int x,y;}a[N];
std::vector<int> vec[N];
LL c[N];
bool vis[N];

bool cmp(data a,data b)
{
	return a.x<b.x||a.x==b.x&&a.y<b.y;
}

LL get(int x)
{
	return (LL)x*(x+1)/2;
}

void ins(int x,int y)
{
	while (x<=n) c[x]+=y,x+=x&(-x);
}

int find(int x)
{
	int ans=0;
	while (x) ans+=c[x],x-=x&(-x);
	return ans;
}

int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y);
	for (int i=1;i<=n;i++) t[i]=a[i].x;
	std::sort(t+1,t+n+1);
	for (int i=1;i<=n;i++) a[i].x=std::lower_bound(t+1,t+n+1,a[i].x)-t;
	for (int i=1;i<=n;i++) t[i]=a[i].y;
	std::sort(t+1,t+n+1);
	for (int i=1;i<=n;i++) a[i].y=std::lower_bound(t+1,t+n+1,a[i].y)-t;
	for (int i=1;i<=n;i++) vec[a[i].y].pb(a[i].x);
	LL ans=0;
	for (int i=n;i>=1;i--)
	{
		if (!vec[i].size()) continue;
		int tot=0;
		for (int j=0;j<vec[i].size();j++) b[++tot]=vec[i][j];
		for (int j=1;j<=tot;j++) if (!vis[b[j]]) vis[b[j]]=1,ins(b[j],1);
		ans+=get(find(n));
		ans-=get(find(b[1]-1));
		ans-=get(find(n)-find(b[tot]));
		for (int j=1;j<tot;j++) ans-=get(find(b[j+1]-1)-find(b[j]));
	}
	printf("%lld\n",ans);
	return 0;
}


#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#define pb push_back

typedef long long LL;

const int N=200005;

int n,b[N],ls[N];
struct data{int x,y;}a[N];
std::vector<int> vec[N];

bool cmp(data a,data b)
{
	return a.x<b.x;
}

int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y);
	std::sort(a+1,a+n+1,cmp);
	int m=0;
	for (int i=1;i<=n;i++)
		if (!m||a[i].x!=b[m]) b[++m]=a[i].x,vec[m].pb(a[i].y);
		else vec[m].pb(a[i].y);
	LL now=0,ans=0;
	for (int i=1;i<=m;i++)
	{
		for (int j=0;j<vec[i].size();j++) now+=i-ls[vec[i][j]],ls[vec[i][j]]=i;
		ans+=now;
	}
	printf("%lld\n",ans);
	return 0;
}


//Chaos///

#include<bits/stdc++.h>
//#include <boost/multiprecision/cpp_int.hpp>
//using namespace boost::multiprecision;
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
using namespace std;
#pragma GCC optimize("O3")
#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("unroll-loops")
#if DEBUG && !ONLINE_JUDGE
    #define debug(args...)     (Debugger()) , args
    class Debugger
    {
        public:
        Debugger(const std::string& _separator = ", ") :
        first(true), separator(_separator){}
        template<typename ObjectType>
        Debugger& operator , (const ObjectType& v)
        {
            if(!first)
                std::cerr << separator;
            std::cerr << v;
            first = false;
            return *this;
        }
        ~Debugger() {  std::cerr << endl;}

        private:
        bool first;
        std::string separator;
    };
    template <typename T1, typename T2>
    inline std::ostream& operator << (std::ostream& os, const std::pair<T1, T2>& p)
    {
        return os << "(" << p.first << ", " << p.second << ")";
    }
    template<typename T>
    inline std::ostream &operator << (std::ostream & os,const std::vector<T>& v)
    {
        bool first = true;
        os << "[";
        for(unsigned int i = 0; i < v.size(); i++)
        {
            if(!first)
                os << ", ";
            os << v[i];
            first = false;
        }
        return os << "]";
    }
    template<typename T>
    inline std::ostream &operator << (std::ostream & os,const std::set<T>& v)
    {
        bool first = true;
        os << "[";
        for (typename std::set<T>::const_iterator ii = v.begin(); ii != v.end(); ++ii)
        {
            if(!first)
                os << ", ";
            os << *ii;
            first = false;
        }
        return os << "]";
    }
    template<typename T1, typename T2>
    inline std::ostream &operator << (std::ostream & os,const std::map<T1, T2>& v)
    {
        bool first = true;
        os << "[";
        for (typename std::map<T1, T2>::const_iterator ii = v.begin(); ii != v.end(); ++ii)
        {
            if(!first)
                os << ", ";
            os << *ii ;
            first = false;
        }
        return os << "]";
    }
#else
    #define debug(args...)
#endif
const int mod = 1000000007;
// const int mod = 998244353;
#define ok order_of_key
#define fo find_by_order
#define ordered_set tree<int, null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update>
#define ll long long
#define rep(i,a,b) for(int i=(a);i<(b);i++)
#define repp(i,n) for(int i=(0);i<(n);i++)
#define repr(i,n) for(int i=(n);i>=0;i--)
#define reprr(i,n) for(int i=(n);i>0;i--)
#define repl(i,a,b) for(ll i=(a);i<(b);i++)
#define newl cout<<'\n'
#define inf 1000000000
#define repaa(i,a) for(auto i=a.begin();i!=a.end();++i)
#define pb push_back
#define test cout<<"test"<<endl
#define tc int tt;cin>>tt;while(tt--)
#define start int tt;tt=read();while(tt--)
#define nl "\n"
#define startk int tt;cin>>tt;for(int kk=1;kk<=tt;kk++)
#define mem(v,i) memset(v,i,sizeof(v))//Use mem(v,60) to initialize with 10^9
#define all(x) x.begin(), x.end()
#define inf1 1e18
#define repa(i,a) for (auto i : a)
#define X first
#define Y second
#define lb lower_bound
#define ub upper_bound
#define gcd(a,b)    __gcd((a),(b))
#define lcm(a,b)    ((a)*(b)) / gcd((a),(b))
#define dec(v) sort(v.begin(),v.end(),greater<int>());
#define in(a,n) repp(jjj,n)cin>>a[jjj];
#define re(a,n) repp(jjj,n)a[jjj]=read();
#define retree(a,m) repp(i,m){int tmp1=read()-1,tmp2=read()-1;a[tmp1].eb(tmp2);a[tmp2].eb(tmp1);}
#define intree(a,m) repp(i,m){int tmp1,tmp2;cin>>tmp1>>tmp2;tmp1--,tmp2--;a[tmp1].eb(tmp2);a[tmp2].eb(tmp1);}
#define ins insert
#define case(ans) cout << "Case #" << kk << ':' << ' ' << ans << nl
#define er erase
#define sz(a) (int)(a.size())
#define print(x,n,k) repp(i,n){repp(j,k)cout<<x[i][j]<<"  ";newl;}
#define mt make_tuple
#define eb emplace_back
#define bp(i) __builtin_popcountll(i)
#define precision(x) cout << fixed << setprecision(x);
#define si set<int>
#define usi unordered_set<int>
#define sl set < ll >
#define usl unordered_set < ll >
#define sip set < ip >
#define sil set < il >
#define mi map<int , int >
#define umi unordered_map<int , int >
#define ml map < ll , ll>
#define uml unordered_map < ll , ll>
#define mip map<ip , int>
#define mmx(x1,x2) min(x1,x2) , max(x1,x2)
#define make_unique(x) sort(all((x))); (x).resize(unique(all((x))) - (x).begin())
#define mxe max_element
#define mne min_element
#define srt(v) sort(all(v))
#define rsrt(v) sort(v.rbegin(), v.rend())
#define yn {puts("YES");}else{puts("NO");}
typedef long double ld;
typedef vector<int> vi;
typedef vector<char> vc;
typedef vector<ll> vl;
typedef vector < vi > vii;
typedef vector<pair<int,int>> vip;
typedef vector<pair<ll,ll>> vil;
typedef vector < vl > vll;
typedef pair<int, int> ip;
typedef pair<ll, ll> il;
typedef tuple<int,int,int> state;
typedef tuple<ll,ll,ll> statel;
const int dx[4]={1,0,0,-1};
const int dy[4]={0,1,-1,0};
const int dxo[8] = {-1, -1, -1, 0, 1, 1, 1, 0};
const int dyo[8] = {-1, 0, 1, 1, 1, 0, -1, -1};
const double eps = 1e-10;
#ifdef Fading
#define gc getchar
#endif
#ifndef Fading
inline char gc(){static char now[1<<16],*S,*T;if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}return *S++;}
#endif
inline ll read(){register ll x=0,f=1;char ch=gc();while (!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}while (isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=gc();}return (f==1)?x:-x;}
template<typename T>T Min(T v) {return v;}template<typename T, typename... Args>T Min(T first, Args... args) {return min(first , Min(args...));}
template<typename T>T Max(T v) {return v;}
template<typename T, typename... Args> T Max(T first, Args... args) {return max(first , Max(args...));}
template<typename T> T mult(T v) {return v;} template<typename T, typename... Args>T mult(T first, Args... args) {return mult((first%mod * mult(args...))%mod);}
template<class T , class U> inline bool remax(T &a, U b) { return a < b ? a = b, 1 : 0; }
template<class T , class U> inline bool remin(T &a, U b) { return a > b ? a = b, 1 : 0; }
template<class A, class B> void add(A &a, B b){a += b;if(a >= mod) a -= mod;if(a < 0) a += mod;}
template<class A, class B> ll addr(A a, B b){a += b;if(a >= mod) a -= mod;if(a < 0) a += mod;return a;}
template<class T1,class T2>T2 min(T1 a,T2 b){return min((T2)a,b);}
template<class T1,class T2>T2 max(T1 a,T2 b){return max((T2)a,b);}
template <class T1>void kill(T1 ans){cout << ans << endl;exit(0);}
template<class A> void pnt(A a[],int st,int en) {rep(i,st,en) cout << a[i] << ' ' ; newl;}
template<class A> void pnt(A a[],int en) {repp(i,en) cout << a[i] << ' ' ; newl;}
template<class A> void pnt(vectora) {repa(i,a) cout << i << ' ' ; newl;}
template<class A> void pnt(A a) {cout << a << nl;}
template<class A> void pnt(seta) {repa(i,a) cout << i << ' ' ; newl;}
template<class A> void pnt(unordered_seta) {repa(i,a) cout << i << ' ' ; newl;}
template<class A,class B> void pnt(paira){cout << a.X << ' ' << a.Y << nl;}
template<typename T1,typename T2>inline istream& operator>>(istream&i,pair<T1,T2>&v){return i>>v.X>>v.Y;}

ll nc2(ll a){return a * (a - 1) / 2;}
ll setbit(ll num, ll kk){ return 1LL*(num|(1LL<<kk)); }
ll unsetbit(ll num, ll kk){ return 1LL*(num&~(1LL<<kk)); }
ll invertbit(ll num, ll kk){ return 1LL*(num^(1LL<<kk)); }
bool kthbit(ll num, ll kk){ return num&(1LL<<kk); }
bool matchpar(ll a, ll b){return (a&1) == (b&1);}
ll mceil(ll a, ll b){return a/b + (ll)(a%b > 0);}
ll poww(ll a, ll b,ll m = mod){ll val = 1;a %= m;while (b > 0){if (b & 1) val = (a * val) % m;a = (a * a) % m;b >>= 1;}return val;}
ll inv(ll a){return poww(a , mod - 2);}
ll gcdll(ll x, ll y){return y == 0 ? x : gcdll(y, x % y);}
int mylog(ll x , ll y){if(x == 0) return -1;return mylog(x/y,y) + 1;}

//-----------------------------------------------------end--------------------------------------//

signed main()
{
    ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    map < int , vi > mp;
    int n ;
    cin >> n;
    ordered_set support;
    map < int , set < int > > rem;
    set < int > s;
    repp(i,n){
        ip tmp;
        cin >> tmp;
        mp[tmp.Y].eb(tmp.X);
        support.ins(tmp.X);
    }
    for(auto i = mp.rbegin() ; i != mp.rend() ; i ++){
        repa(j,i -> Y){
            if(s.count(j)) continue;
            s.ins(j);
            rem[i -> X].ins(j);
        }
    }
    repa(&i,mp) sort(all(i.Y));
    ll ans = 0;
    repa(i, mp){
        repa(j,i.Y) support.er(j);
        int ch = 0;
        // repa(i,support) cerr << i << ' ' ;
        // cerr << endl;
        int remove = 0;
        repa(j,i.Y){
            // mere se left support elements kitne hai ?
            int left = support.ok(j) - remove;
            remove = support.ok(j);
            // mere se right mei kitne hai ?
            // we also need to remove elements less than prev
            int right = support.size() - remove;
            debug(i.X,j,left,right,(left + 1),(right + i.Y.size() - ch),(left + 1) * (right + i.Y.size() - ch));
            ans += 1LL * (left + 1) * (right + i.Y.size() - ch);
            ch ++;
        }
        repa(j,i.Y) if(!rem[i.X].count(j)) support.ins(j);
    }
    pnt(ans);
}


//Chaos///

#include<bits/stdc++.h>
//#include <boost/multiprecision/cpp_int.hpp>
//using namespace boost::multiprecision;
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
using namespace std;
#pragma GCC optimize("O3")
#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("unroll-loops")
#if DEBUG && !ONLINE_JUDGE
    #define debug(args...)     (Debugger()) , args
    class Debugger
    {
        public:
        Debugger(const std::string& _separator = ", ") :
        first(true), separator(_separator){}
        template<typename ObjectType>
        Debugger& operator , (const ObjectType& v)
        {
            if(!first)
                std::cerr << separator;
            std::cerr << v;
            first = false;
            return *this;
        }
        ~Debugger() {  std::cerr << endl;}

        private:
        bool first;
        std::string separator;
    };
    template <typename T1, typename T2>
    inline std::ostream& operator << (std::ostream& os, const std::pair<T1, T2>& p)
    {
        return os << "(" << p.first << ", " << p.second << ")";
    }
    template<typename T>
    inline std::ostream &operator << (std::ostream & os,const std::vector<T>& v)
    {
        bool first = true;
        os << "[";
        for(unsigned int i = 0; i < v.size(); i++)
        {
            if(!first)
                os << ", ";
            os << v[i];
            first = false;
        }
        return os << "]";
    }
    template<typename T>
    inline std::ostream &operator << (std::ostream & os,const std::set<T>& v)
    {
        bool first = true;
        os << "[";
        for (typename std::set<T>::const_iterator ii = v.begin(); ii != v.end(); ++ii)
        {
            if(!first)
                os << ", ";
            os << *ii;
            first = false;
        }
        return os << "]";
    }
    template<typename T1, typename T2>
    inline std::ostream &operator << (std::ostream & os,const std::map<T1, T2>& v)
    {
        bool first = true;
        os << "[";
        for (typename std::map<T1, T2>::const_iterator ii = v.begin(); ii != v.end(); ++ii)
        {
            if(!first)
                os << ", ";
            os << *ii ;
            first = false;
        }
        return os << "]";
    }
#else
    #define debug(args...)
#endif
const int mod = 1000000007;
// const int mod = 998244353;
#define ok order_of_key
#define fo find_by_order
#define ordered_set tree<int, null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update>
#define ll long long
#define rep(i,a,b) for(int i=(a);i<(b);i++)
#define repp(i,n) for(int i=(0);i<(n);i++)
#define repr(i,n) for(int i=(n);i>=0;i--)
#define reprr(i,n) for(int i=(n);i>0;i--)
#define repl(i,a,b) for(ll i=(a);i<(b);i++)
#define newl cout<<'\n'
#define inf 1000000000
#define repaa(i,a) for(auto i=a.begin();i!=a.end();++i)
#define pb push_back
#define test cout<<"test"<<endl
#define tc int tt;cin>>tt;while(tt--)
#define start int tt;tt=read();while(tt--)
#define nl "\n"
#define startk int tt;cin>>tt;for(int kk=1;kk<=tt;kk++)
#define mem(v,i) memset(v,i,sizeof(v))//Use mem(v,60) to initialize with 10^9
#define all(x) x.begin(), x.end()
#define inf1 1e18
#define repa(i,a) for (auto i : a)
#define X first
#define Y second
#define lb lower_bound
#define ub upper_bound
#define gcd(a,b)    __gcd((a),(b))
#define lcm(a,b)    ((a)*(b)) / gcd((a),(b))
#define dec(v) sort(v.begin(),v.end(),greater<int>());
#define in(a,n) repp(jjj,n)cin>>a[jjj];
#define re(a,n) repp(jjj,n)a[jjj]=read();
#define retree(a,m) repp(i,m){int tmp1=read()-1,tmp2=read()-1;a[tmp1].eb(tmp2);a[tmp2].eb(tmp1);}
#define intree(a,m) repp(i,m){int tmp1,tmp2;cin>>tmp1>>tmp2;tmp1--,tmp2--;a[tmp1].eb(tmp2);a[tmp2].eb(tmp1);}
#define ins insert
#define case(ans) cout << "Case #" << kk << ':' << ' ' << ans << nl
#define er erase
#define sz(a) (int)(a.size())
#define print(x,n,k) repp(i,n){repp(j,k)cout<<x[i][j]<<"  ";newl;}
#define mt make_tuple
#define eb emplace_back
#define bp(i) __builtin_popcountll(i)
#define precision(x) cout << fixed << setprecision(x);
#define si set<int>
#define usi unordered_set<int>
#define sl set < ll >
#define usl unordered_set < ll >
#define sip set < ip >
#define sil set < il >
#define mi map<int , int >
#define umi unordered_map<int , int >
#define ml map < ll , ll>
#define uml unordered_map < ll , ll>
#define mip map<ip , int>
#define mmx(x1,x2) min(x1,x2) , max(x1,x2)
#define make_unique(x) sort(all((x))); (x).resize(unique(all((x))) - (x).begin())
#define mxe max_element
#define mne min_element
#define srt(v) sort(all(v))
#define rsrt(v) sort(v.rbegin(), v.rend())
#define yn {puts("YES");}else{puts("NO");}
typedef long double ld;
typedef vector<int> vi;
typedef vector<char> vc;
typedef vector<ll> vl;
typedef vector < vi > vii;
typedef vector<pair<int,int>> vip;
typedef vector<pair<ll,ll>> vil;
typedef vector < vl > vll;
typedef pair<int, int> ip;
typedef pair<ll, ll> il;
typedef tuple<int,int,int> state;
typedef tuple<ll,ll,ll> statel;
const int dx[4]={1,0,0,-1};
const int dy[4]={0,1,-1,0};
const int dxo[8] = {-1, -1, -1, 0, 1, 1, 1, 0};
const int dyo[8] = {-1, 0, 1, 1, 1, 0, -1, -1};
const double eps = 1e-10;
#ifdef Fading
#define gc getchar
#endif
#ifndef Fading
inline char gc(){static char now[1<<16],*S,*T;if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}return *S++;}
#endif
inline ll read(){register ll x=0,f=1;char ch=gc();while (!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}while (isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=gc();}return (f==1)?x:-x;}
template<typename T>T Min(T v) {return v;}template<typename T, typename... Args>T Min(T first, Args... args) {return min(first , Min(args...));}
template<typename T>T Max(T v) {return v;}
template<typename T, typename... Args> T Max(T first, Args... args) {return max(first , Max(args...));}
template<typename T> T mult(T v) {return v;} template<typename T, typename... Args>T mult(T first, Args... args) {return mult((first%mod * mult(args...))%mod);}
template<class T , class U> inline bool remax(T &a, U b) { return a < b ? a = b, 1 : 0; }
template<class T , class U> inline bool remin(T &a, U b) { return a > b ? a = b, 1 : 0; }
template<class A, class B> void add(A &a, B b){a += b;if(a >= mod) a -= mod;if(a < 0) a += mod;}
template<class A, class B> ll addr(A a, B b){a += b;if(a >= mod) a -= mod;if(a < 0) a += mod;return a;}
template<class T1,class T2>T2 min(T1 a,T2 b){return min((T2)a,b);}
template<class T1,class T2>T2 max(T1 a,T2 b){return max((T2)a,b);}
template <class T1>void kill(T1 ans){cout << ans << endl;exit(0);}
template<class A> void pnt(A a[],int st,int en) {rep(i,st,en) cout << a[i] << ' ' ; newl;}
template<class A> void pnt(A a[],int en) {repp(i,en) cout << a[i] << ' ' ; newl;}
template<class A> void pnt(vectora) {repa(i,a) cout << i << ' ' ; newl;}
template<class A> void pnt(A a) {cout << a << nl;}
template<class A> void pnt(seta) {repa(i,a) cout << i << ' ' ; newl;}
template<class A> void pnt(unordered_seta) {repa(i,a) cout << i << ' ' ; newl;}
template<class A,class B> void pnt(paira){cout << a.X << ' ' << a.Y << nl;}
template<typename T1,typename T2>inline istream& operator>>(istream&i,pair<T1,T2>&v){return i>>v.X>>v.Y;}

ll nc2(ll a){return a * (a - 1) / 2;}
ll setbit(ll num, ll kk){ return 1LL*(num|(1LL<<kk)); }
ll unsetbit(ll num, ll kk){ return 1LL*(num&~(1LL<<kk)); }
ll invertbit(ll num, ll kk){ return 1LL*(num^(1LL<<kk)); }
bool kthbit(ll num, ll kk){ return num&(1LL<<kk); }
bool matchpar(ll a, ll b){return (a&1) == (b&1);}
ll mceil(ll a, ll b){return a/b + (ll)(a%b > 0);}
ll poww(ll a, ll b,ll m = mod){ll val = 1;a %= m;while (b > 0){if (b & 1) val = (a * val) % m;a = (a * a) % m;b >>= 1;}return val;}
ll inv(ll a){return poww(a , mod - 2);}
ll gcdll(ll x, ll y){return y == 0 ? x : gcdll(y, x % y);}
int mylog(ll x , ll y){if(x == 0) return -1;return mylog(x/y,y) + 1;}

//-----------------------------------------------------end--------------------------------------//

signed main()
{
    ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    map < int , vi > mp;
    int n ;
    cin >> n;
    ordered_set support;
    map < int , set < int > > rem;
    set < int > s;
    repp(i,n){
        ip tmp;
        cin >> tmp;
        mp[tmp.Y].eb(tmp.X);
        support.ins(tmp.X);
    }
    for(auto i = mp.rbegin() ; i != mp.rend() ; i ++){
        repa(j,i -> Y){
            if(s.count(j)) continue;
            s.ins(j);
            rem[i -> X].ins(j);
        }
    }
    repa(&i,mp) sort(all(i.Y));
    ll ans = 0;
    repa(i, mp){
        repa(j,i.Y) support.er(j);
        int ch = 0;
        repa(j,i.Y){
            // mere se left support elements kitne hai ?
            int left = support.ok(j);
            // mere se right mei kitne hai ?
            int right = support.size() - left;
            debug(i.X,j,left,right,(left + 1),(right + i.Y.size() - ch));
            ans += 1LL * (left + 1) * (right + i.Y.size() - ch);
            ch ++;
        }
        repa(j,i.Y) if(!rem[i.X].count(j)) support.ins(j);
    }
    pnt(ans);
}


//Chaos///

#include<bits/stdc++.h>
//#include <boost/multiprecision/cpp_int.hpp>
//using namespace boost::multiprecision;
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
using namespace std;
#pragma GCC optimize("O3")
#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("unroll-loops")
#if DEBUG && !ONLINE_JUDGE
    #define debug(args...)     (Debugger()) , args
    class Debugger
    {
        public:
        Debugger(const std::string& _separator = ", ") :
        first(true), separator(_separator){}
        template<typename ObjectType>
        Debugger& operator , (const ObjectType& v)
        {
            if(!first)
                std::cerr << separator;
            std::cerr << v;
            first = false;
            return *this;
        }
        ~Debugger() {  std::cerr << endl;}

        private:
        bool first;
        std::string separator;
    };
    template <typename T1, typename T2>
    inline std::ostream& operator << (std::ostream& os, const std::pair<T1, T2>& p)
    {
        return os << "(" << p.first << ", " << p.second << ")";
    }
    template<typename T>
    inline std::ostream &operator << (std::ostream & os,const std::vector<T>& v)
    {
        bool first = true;
        os << "[";
        for(unsigned int i = 0; i < v.size(); i++)
        {
            if(!first)
                os << ", ";
            os << v[i];
            first = false;
        }
        return os << "]";
    }
    template<typename T>
    inline std::ostream &operator << (std::ostream & os,const std::set<T>& v)
    {
        bool first = true;
        os << "[";
        for (typename std::set<T>::const_iterator ii = v.begin(); ii != v.end(); ++ii)
        {
            if(!first)
                os << ", ";
            os << *ii;
            first = false;
        }
        return os << "]";
    }
    template<typename T1, typename T2>
    inline std::ostream &operator << (std::ostream & os,const std::map<T1, T2>& v)
    {
        bool first = true;
        os << "[";
        for (typename std::map<T1, T2>::const_iterator ii = v.begin(); ii != v.end(); ++ii)
        {
            if(!first)
                os << ", ";
            os << *ii ;
            first = false;
        }
        return os << "]";
    }
#else
    #define debug(args...)
#endif
const int mod = 1000000007;
// const int mod = 998244353;
#define ok order_of_key
#define fo find_by_order
#define ordered_set tree<int, null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update>
#define ll long long
#define rep(i,a,b) for(int i=(a);i<(b);i++)
#define repp(i,n) for(int i=(0);i<(n);i++)
#define repr(i,n) for(int i=(n);i>=0;i--)
#define reprr(i,n) for(int i=(n);i>0;i--)
#define repl(i,a,b) for(ll i=(a);i<(b);i++)
#define newl cout<<'\n'
#define inf 1000000000
#define repaa(i,a) for(auto i=a.begin();i!=a.end();++i)
#define pb push_back
#define test cout<<"test"<<endl
#define tc int tt;cin>>tt;while(tt--)
#define start int tt;tt=read();while(tt--)
#define nl "\n"
#define startk int tt;cin>>tt;for(int kk=1;kk<=tt;kk++)
#define mem(v,i) memset(v,i,sizeof(v))//Use mem(v,60) to initialize with 10^9
#define all(x) x.begin(), x.end()
#define inf1 1e18
#define repa(i,a) for (auto i : a)
#define X first
#define Y second
#define lb lower_bound
#define ub upper_bound
#define gcd(a,b)    __gcd((a),(b))
#define lcm(a,b)    ((a)*(b)) / gcd((a),(b))
#define dec(v) sort(v.begin(),v.end(),greater<int>());
#define in(a,n) repp(jjj,n)cin>>a[jjj];
#define re(a,n) repp(jjj,n)a[jjj]=read();
#define retree(a,m) repp(i,m){int tmp1=read()-1,tmp2=read()-1;a[tmp1].eb(tmp2);a[tmp2].eb(tmp1);}
#define intree(a,m) repp(i,m){int tmp1,tmp2;cin>>tmp1>>tmp2;tmp1--,tmp2--;a[tmp1].eb(tmp2);a[tmp2].eb(tmp1);}
#define ins insert
#define case(ans) cout << "Case #" << kk << ':' << ' ' << ans << nl
#define er erase
#define sz(a) (int)(a.size())
#define print(x,n,k) repp(i,n){repp(j,k)cout<<x[i][j]<<"  ";newl;}
#define mt make_tuple
#define eb emplace_back
#define bp(i) __builtin_popcountll(i)
#define precision(x) cout << fixed << setprecision(x);
#define si set<int>
#define usi unordered_set<int>
#define sl set < ll >
#define usl unordered_set < ll >
#define sip set < ip >
#define sil set < il >
#define mi map<int , int >
#define umi unordered_map<int , int >
#define ml map < ll , ll>
#define uml unordered_map < ll , ll>
#define mip map<ip , int>
#define mmx(x1,x2) min(x1,x2) , max(x1,x2)
#define make_unique(x) sort(all((x))); (x).resize(unique(all((x))) - (x).begin())
#define mxe max_element
#define mne min_element
#define srt(v) sort(all(v))
#define rsrt(v) sort(v.rbegin(), v.rend())
#define yn {puts("YES");}else{puts("NO");}
typedef long double ld;
typedef vector<int> vi;
typedef vector<char> vc;
typedef vector<ll> vl;
typedef vector < vi > vii;
typedef vector<pair<int,int>> vip;
typedef vector<pair<ll,ll>> vil;
typedef vector < vl > vll;
typedef pair<int, int> ip;
typedef pair<ll, ll> il;
typedef tuple<int,int,int> state;
typedef tuple<ll,ll,ll> statel;
const int dx[4]={1,0,0,-1};
const int dy[4]={0,1,-1,0};
const int dxo[8] = {-1, -1, -1, 0, 1, 1, 1, 0};
const int dyo[8] = {-1, 0, 1, 1, 1, 0, -1, -1};
const double eps = 1e-10;
#ifdef Fading
#define gc getchar
#endif
#ifndef Fading
inline char gc(){static char now[1<<16],*S,*T;if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}return *S++;}
#endif
inline ll read(){register ll x=0,f=1;char ch=gc();while (!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}while (isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=gc();}return (f==1)?x:-x;}
template<typename T>T Min(T v) {return v;}template<typename T, typename... Args>T Min(T first, Args... args) {return min(first , Min(args...));}
template<typename T>T Max(T v) {return v;}
template<typename T, typename... Args> T Max(T first, Args... args) {return max(first , Max(args...));}
template<typename T> T mult(T v) {return v;} template<typename T, typename... Args>T mult(T first, Args... args) {return mult((first%mod * mult(args...))%mod);}
template<class T , class U> inline bool remax(T &a, U b) { return a < b ? a = b, 1 : 0; }
template<class T , class U> inline bool remin(T &a, U b) { return a > b ? a = b, 1 : 0; }
template<class A, class B> void add(A &a, B b){a += b;if(a >= mod) a -= mod;if(a < 0) a += mod;}
template<class A, class B> ll addr(A a, B b){a += b;if(a >= mod) a -= mod;if(a < 0) a += mod;return a;}
template<class T1,class T2>T2 min(T1 a,T2 b){return min((T2)a,b);}
template<class T1,class T2>T2 max(T1 a,T2 b){return max((T2)a,b);}
template <class T1>void kill(T1 ans){cout << ans << endl;exit(0);}
template<class A> void pnt(A a[],int st,int en) {rep(i,st,en) cout << a[i] << ' ' ; newl;}
template<class A> void pnt(A a[],int en) {repp(i,en) cout << a[i] << ' ' ; newl;}
template<class A> void pnt(vectora) {repa(i,a) cout << i << ' ' ; newl;}
template<class A> void pnt(A a) {cout << a << nl;}
template<class A> void pnt(seta) {repa(i,a) cout << i << ' ' ; newl;}
template<class A> void pnt(unordered_seta) {repa(i,a) cout << i << ' ' ; newl;}
template<class A,class B> void pnt(paira){cout << a.X << ' ' << a.Y << nl;}
template<typename T1,typename T2>inline istream& operator>>(istream&i,pair<T1,T2>&v){return i>>v.X>>v.Y;}

ll nc2(ll a){return a * (a - 1) / 2;}
ll setbit(ll num, ll kk){ return 1LL*(num|(1LL<<kk)); }
ll unsetbit(ll num, ll kk){ return 1LL*(num&~(1LL<<kk)); }
ll invertbit(ll num, ll kk){ return 1LL*(num^(1LL<<kk)); }
bool kthbit(ll num, ll kk){ return num&(1LL<<kk); }
bool matchpar(ll a, ll b){return (a&1) == (b&1);}
ll mceil(ll a, ll b){return a/b + (ll)(a%b > 0);}
ll poww(ll a, ll b,ll m = mod){ll val = 1;a %= m;while (b > 0){if (b & 1) val = (a * val) % m;a = (a * a) % m;b >>= 1;}return val;}
ll inv(ll a){return poww(a , mod - 2);}
ll gcdll(ll x, ll y){return y == 0 ? x : gcdll(y, x % y);}
int mylog(ll x , ll y){if(x == 0) return -1;return mylog(x/y,y) + 1;}

//-----------------------------------------------------end--------------------------------------//

signed main()
{
    ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    mi mp;
    int n ;
    cin >> n;
    repp(i,n){
        ip tmp;
        cin >> tmp;
        mp[tmp.Y] ++;
    }
    ll ans = 0;
    repa(i,mp) ans += nc2(i.Y + 1);
    pnt(ans);
}


//
//  main.cpp
//  A
//
//  Created by E SAMEER KUMAR on 09/04/20.
//  Copyright © 2020 E SAMEER KUMAR. All rights reserved.

#include <bits/stdc++.h>
using ll = long long;
using namespace std;
//map<int,vector<int>> tree;
//map<int,vector<int>> rooted;
//map<int,int> primes;
void debugi(vector<int> & vec){
    int n=(int)vec.size();
    for(int i=0;i<n;i++){
        cout<<vec[i]<<" ";
    }
    cout<<endl;
}
void debugl(vector<ll> & vec){
    int n=(int)vec.size();
    for(int i=0;i<n;i++){
        cout<<vec[i]<<" ";
    }
    cout<<endl;
}
void debugmap(map<int,int> & mp){
    for(auto x:mp){
        cout<<x.first<<" "<<x.second<<" , ";
    }
    cout<<endl;
}
void debugset(set<int> & st){
    for(auto x: st){
        cout<<x<<" ";
    }
    cout<<endl;
}
void debugparri(vector<pair<int, int>>& arr){
    for(int i=0;i<(int)arr.size();i++){
        cout<<"["<<arr[i].first<<" : "<<arr[i].second<<"]"<<" ";
    }
    cout<<endl;
}
void debugpi(pair<int, int> &pi){
    cout<<pi.first<<" "<<pi.second<<endl;
}
void debugq(queue<int> q){
    while(!q.empty()){
        cout<<q.front()<<" ";
        q.pop();
    }
    cout<<endl;
}

bool check(int n,int i,int j){
    if((0<=i & i<n) && (0<=j & j<n)){
        return true;
    }
    return false;
}
ll MOD = 1e9+7;
ll powab(ll a,ll b,ll mod){
    if(b==0){
        return 1;
    }
    ll z=powab(a, b/2, mod);
    ll res=(z*z*1LL)%mod;
    if(b&1){
        res=(res*1LL*a)%mod;
    }
    return res;
}
//ll modinv(ll a){
//    ll ans=powab(a, mod-2, mod);
//    return ans;
//}
void upd(int k, int x,vector<int>& tree,int n){
//    cout<<k<<" k "<<endl;
    if(k==0){
        return;
    }
//    cout<<k<<" k "<<endl;
    while(k<=n){
//        cout<<k<<" kk "<<endl;
        tree[k]+=x;
        k+=(k&-k);
    }
}
int sum(int k,vector<int>& tree,int n){
    int s=0;
    while(k>=1){
        s+=tree[k];
        k-=(k&-k);
    }
    return s;
}
// char s[100006];
// int m=200005;
// int p;
//int mod(int x,int mod){
//    if(x<0){
//        return mod-(x%mod);
//    }
//    else{
//        return x%mod;
//    }
//}
ll gcd(ll a, ll b){
    if(b==0){
        return a;
    }
    return gcd(b,a%b);
}
// int ans=0,n,m;
int main(int argc, const char * argv[]) {
    // insert code here...
    // ofstream file;
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    int n;
    cin>>n;
    map<int,vector<int>> mp;
    map<int,int> mpy,mpx;
    vector<int>vx,vy;
    for(int i=0;i<n;i++){
        int x,y;
        cin>>x>>y;
        mp[y].push_back(x);
        if(mpx[x]==0){
            vx.push_back(x);
            mpx[x]=1;
        }
        if(mpy[y]==0){
            vy.push_back(y);
            mpy[y]=1;
        }
    }
    for(auto y: mp){
        sort(mp[y.first].begin(),mp[y.first].end());
    }
    int m=vx.size();
    sort(vx.begin(),vx.end());
    map<int,int> indx;
    for(int i=0;i<m;i++){
        indx[vx[i]]=i;
    }
    vector<int> treex(m+1);
    sort(vy.begin(),vy.end());
    reverse(vy.begin(),vy.end());
    int k=vy.size();
    ll ans=0;
    map<int,int> visx;
    for(int i=0;i<k;i++){
        int a=mp[vy[i]].size();
        // cout<<a<<" a "<<endl;
        int prevl=0,prevr=0,lastl=0;
        for(int j=0;j<a;j++){
            int x=mp[vy[i]][j];
            int ind=indx[x];
            if(visx[x]==0){
                // int ind=indx[x];
                upd(ind+1,1,treex,m);
                visx[x]=1;
            }
            int sub=0;
            for(int g=j+1;g<a;g++){
                if(visx[mp[vy[i]][g]]){
                    sub+=1;
                }
            }
            int left=sum(ind,treex,m);
            int right=sum(m,treex,m);
            // cout<<left<<" leftt "<<right<<" rightt "<<endl;
            int indl=j,indr=a-j-1-sub;
            // cout<<indl<<" indl "<<indr<<" indr "<<endl;
            int r=right-(left+1);
            // debugi(treex);
            // cout<<left<<" left "<<right<<" right "<<x<<" x "<<ind<<" ind "<<endl;
            // cout<<left+1-indl<<" "<<r+1+indr<<" "<<x<<" x "<<vy[i]<<" y "<<endl;
            // ll add=(left-indl+r+indr+1;

            ll add=(left+1-indl-lastl)*1LL*(r+1+indr);
            int lastl=(left+1-indl);
            // prevl=left+1-indl;prevr=r+1+indr;
            // left+=1;
            // ll add=(left+1)*1LL;
            ans+=add;
        }
    }
    cout<<ans<<endl;
    // for(int i=0;i<n;i++){
    //     int x,y;
    //     cin>>x>>y;
    //     mp[y].push_back(x);
    //     if(mpx[x]==0){
    //         vx.push_back(x);
    //         mpx[x]=1;
    //     }
    //     if(mpy[y]==0){
    //         vy.push_back(y);
    //         mpy[y]=1;
    //     }
    // }
    // for(auto x:mp){
    //     sort(mp[x].begin(),mp[x].end());
    // }
    // map<int,ll> cnty;
    // ll ans=0;
    // sort(vx.begin(),vx.end());
    // sort(vy.begin(),vy.end());
    // int m=vx.size(),k=vy.size();
    // for(int i=m-1;i>=0;i--){
    //     // int k=y.size();
    //     ll prev=0;
    //     for(auto y:mp[vx[i]]){
    //         cout<<vx[i]<<" vxi "<<y<<" y  "<<endl;
    //         cnty[y]+=1;
    //     }
    //     int a=mp[vx[i]].size();
    //     for(int j=a;j>=0;j--){
    //         int nxt=0;
    //         if(j-1>=0){
    //             nxt=mp[vx[i]][j-1];
    //         }
    //         for(int )
    //     }
    //     for(int j=k-1;j>=0;j--){
    //         prev+=cnty[vy[j]];
    //     }
    //     ans+=prev;
    // }
    // cout<<ans<<endl;
    // for(auto x:mp){
    //     sort(x.second.begin(),x.second.end());
    //     debugi(x.second);
    // }
    // ll ans=0;
    // for(auto i=mp.rbegin(); i!=mp.rend(); i++){
    //     int m=i->second.size();
    //     cout<<m<<" m "<<endl;
    //     mpx[i->first]+=1;
    //     // mpy[y.first]+=1;
    //     for(int j=m-1;j>=0;j--){
    //         cout<<j<<" j "<<endl;
    //         mpy[i->second[j]]+=1;

    //         if(j-1>=0){
    //             last=
    //         }
    //         for(auto y:mpy){

    //             cout<<y.first<<" y "<<endl;
    //             ans+=mpy[y.first];
    //         }
    //     }

    // }
    // cout<<ans<<endl;
}


//
//  main.cpp
//  A
//
//  Created by E SAMEER KUMAR on 09/04/20.
//  Copyright © 2020 E SAMEER KUMAR. All rights reserved.

#include <bits/stdc++.h>
using ll = long long;
using namespace std;
//map<int,vector<int>> tree;
//map<int,vector<int>> rooted;
//map<int,int> primes;
void debugi(vector<int> & vec){
    int n=(int)vec.size();
    for(int i=0;i<n;i++){
        cout<<vec[i]<<" ";
    }
    cout<<endl;
}
void debugl(vector<ll> & vec){
    int n=(int)vec.size();
    for(int i=0;i<n;i++){
        cout<<vec[i]<<" ";
    }
    cout<<endl;
}
void debugmap(map<int,int> & mp){
    for(auto x:mp){
        cout<<x.first<<" "<<x.second<<" , ";
    }
    cout<<endl;
}
void debugset(set<int> & st){
    for(auto x: st){
        cout<<x<<" ";
    }
    cout<<endl;
}
void debugparri(vector<pair<int, int>>& arr){
    for(int i=0;i<(int)arr.size();i++){
        cout<<"["<<arr[i].first<<" : "<<arr[i].second<<"]"<<" ";
    }
    cout<<endl;
}
void debugpi(pair<int, int> &pi){
    cout<<pi.first<<" "<<pi.second<<endl;
}
void debugq(queue<int> q){
    while(!q.empty()){
        cout<<q.front()<<" ";
        q.pop();
    }
    cout<<endl;
}

bool check(int n,int i,int j){
    if((0<=i & i<n) && (0<=j & j<n)){
        return true;
    }
    return false;
}
ll MOD = 1e9+7;
ll powab(ll a,ll b,ll mod){
    if(b==0){
        return 1;
    }
    ll z=powab(a, b/2, mod);
    ll res=(z*z*1LL)%mod;
    if(b&1){
        res=(res*1LL*a)%mod;
    }
    return res;
}
//ll modinv(ll a){
//    ll ans=powab(a, mod-2, mod);
//    return ans;
//}
void upd(int k, int x,vector<int>& tree,int n){
//    cout<<k<<" k "<<endl;
    if(k==0){
        return;
    }
//    cout<<k<<" k "<<endl;
    while(k<=n){
//        cout<<k<<" kk "<<endl;
        tree[k]+=x;
        k+=(k&-k);
    }
}
int sum(int k,vector<int>& tree,int n){
    int s=0;
    while(k>=1){
        s+=tree[k];
        k-=(k&-k);
    }
    return s;
}
// char s[100006];
// int m=200005;
// int p;
//int mod(int x,int mod){
//    if(x<0){
//        return mod-(x%mod);
//    }
//    else{
//        return x%mod;
//    }
//}
ll gcd(ll a, ll b){
    if(b==0){
        return a;
    }
    return gcd(b,a%b);
}
// int ans=0,n,m;
int main(int argc, const char * argv[]) {
    // insert code here...
    // ofstream file;
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    int n;
    cin>>n;
    map<int,vector<int>> mp;
    map<int,int> mpy,mpx;
    vector<int>vx,vy;
    for(int i=0;i<n;i++){
        int x,y;
        cin>>x>>y;
        mp[y].push_back(x);
        if(mpx[x]==0){
            vx.push_back(x);
            mpx[x]=1;
        }
        if(mpy[y]==0){
            vy.push_back(y);
            mpy[y]=1;
        }
    }
    for(auto y: mp){
        sort(mp[y.first].begin(),mp[y.first].end());
    }
    int m=vx.size();
    sort(vx.begin(),vx.end());
    map<int,int> indx;
    for(int i=0;i<m;i++){
        indx[vx[i]]=i;
    }
    vector<int> treex(m+1);
    sort(vy.begin(),vy.end());
    reverse(vy.begin(),vy.end());
    int k=vy.size();
    ll ans=0;
    map<int,int> visx;
    for(int i=0;i<k;i++){
        int a=mp[vy[i]].size();
        // cout<<a<<" a "<<endl;
        int prevl=0,prevr=0,lastl=0,sub=0;
        for(int g=0;g<a;g++){
            if(visx[mp[vy[i]][g]]){
                    sub+=1;
                }
        }
        for(int j=0;j<a;j++){
            int x=mp[vy[i]][j];
            int ind=indx[x];
            if(visx[x]){
                sub-=1;
            }
            if(visx[x]==0){
                // int ind=indx[x];
                upd(ind+1,1,treex,m);
                visx[x]=1;
            }

            // for(int g=j+1;g<a;g++){
            //     if(visx[mp[vy[i]][g]]){
            //         sub+=1;
            //     }
            // }
            int left=sum(ind,treex,m);
            int right=sum(m,treex,m);
            // cout<<left<<" leftt "<<right<<" rightt "<<endl;
            int indl=j,indr=a-j-1-sub;
            // cout<<indl<<" indl "<<indr<<" indr "<<endl;
            int r=right-(left+1);
            // debugi(treex);
            // cout<<left<<" left "<<right<<" right "<<x<<" x "<<ind<<" ind "<<endl;
            // cout<<left+1-indl<<" "<<r+1+indr<<" "<<x<<" x "<<vy[i]<<" y "<<lastl<<" lastl "<<endl;
            // ll add=(left-indl+r+indr+1;
            // cout<<lastl<<" lastl "<<
            ll add=(left+1-indl-lastl)*1LL*(r+1+indr);
            lastl=(left-indl);
            // prevl=left+1-indl;prevr=r+1+indr;
            // left+=1;
            // ll add=(left+1)*1LL;
            ans+=add;
        }
    }
    cout<<ans<<endl;
    // for(int i=0;i<n;i++){
    //     int x,y;
    //     cin>>x>>y;
    //     mp[y].push_back(x);
    //     if(mpx[x]==0){
    //         vx.push_back(x);
    //         mpx[x]=1;
    //     }
    //     if(mpy[y]==0){
    //         vy.push_back(y);
    //         mpy[y]=1;
    //     }
    // }
    // for(auto x:mp){
    //     sort(mp[x].begin(),mp[x].end());
    // }
    // map<int,ll> cnty;
    // ll ans=0;
    // sort(vx.begin(),vx.end());
    // sort(vy.begin(),vy.end());
    // int m=vx.size(),k=vy.size();
    // for(int i=m-1;i>=0;i--){
    //     // int k=y.size();
    //     ll prev=0;
    //     for(auto y:mp[vx[i]]){
    //         cout<<vx[i]<<" vxi "<<y<<" y  "<<endl;
    //         cnty[y]+=1;
    //     }
    //     int a=mp[vx[i]].size();
    //     for(int j=a;j>=0;j--){
    //         int nxt=0;
    //         if(j-1>=0){
    //             nxt=mp[vx[i]][j-1];
    //         }
    //         for(int )
    //     }
    //     for(int j=k-1;j>=0;j--){
    //         prev+=cnty[vy[j]];
    //     }
    //     ans+=prev;
    // }
    // cout<<ans<<endl;
    // for(auto x:mp){
    //     sort(x.second.begin(),x.second.end());
    //     debugi(x.second);
    // }
    // ll ans=0;
    // for(auto i=mp.rbegin(); i!=mp.rend(); i++){
    //     int m=i->second.size();
    //     cout<<m<<" m "<<endl;
    //     mpx[i->first]+=1;
    //     // mpy[y.first]+=1;
    //     for(int j=m-1;j>=0;j--){
    //         cout<<j<<" j "<<endl;
    //         mpy[i->second[j]]+=1;

    //         if(j-1>=0){
    //             last=
    //         }
    //         for(auto y:mpy){

    //             cout<<y.first<<" y "<<endl;
    //             ans+=mpy[y.first];
    //         }
    //     }

    // }
    // cout<<ans<<endl;
}


#include <bits/stdc++.h>
using ll = long long;
using namespace std;
int main(int argc, const char * argv[]) {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    int n;
    cin>>n;
    map<int,vector<int>> mp;
    map<int,int> mpy,mpx;
    vector<int>vx,vy;
    for(int i=0;i<n;i++){
        int x,y;
        cin>>x>>y;
        mp[y].push_back(x);
        if(mpx[x]==0){
            vx.push_back(x);
            mpx[x]=1;
        }
        if(mpy[y]==0){
            vy.push_back(y);
            mpy[y]=1;
        }
    }
    for(auto y: mp){
        sort(mp[y.first].begin(),mp[y.first].end());
    }
    int m=vx.size();
    sort(vx.begin(),vx.end());
    map<int,int> indx;
    for(int i=0;i<m;i++){
        indx[vx[i]]=i;
    }
    vector<int> treex(m+1);
    sort(vy.begin(),vy.end());
    reverse(vy.begin(),vy.end());
    int k=vy.size();
    ll ans=0;
    map<int,int> visx;
    for(int i=0;i<k;i++){
        int a=mp[vy[i]].size();
        int prevl=0,prevr=0,lastl=0,sub=0;
        for(int g=0;g<a;g++){
            if(visx[mp[vy[i]][g]]){
                    sub+=1;
                }
        }
        for(int j=0;j<a;j++){
            int x=mp[vy[i]][j];
            int ind=indx[x];
            if(visx[x]){
                sub-=1;
            }
            if(visx[x]==0){
                upd(ind+1,1,treex,m);
                visx[x]=1;
            }
            int left=sum(ind,treex,m);
            int right=sum(m,treex,m);
            int indl=j,indr=a-j-1-sub;
            int r=right-(left+1);
            ll add=(left+1-indl-lastl)*1LL*(r+1+indr);
            lastl=(left-indl);
            ans+=add;
        }
    }
    cout<<ans<<endl;
}


#include <bits/stdc++.h>
using ll = long long;
using namespace std;

void upd(int k, int x,vector<int>& tree,int n){
    if(k==0){
        return;
    }
    while(k<=n){
        tree[k]+=x;
        k+=(k&-k);
    }
}
int sum(int k,vector<int>& tree,int n){
    int s=0;
    while(k>=1){
        s+=tree[k];
        k-=(k&-k);
    }
    return s;
}
int main(int argc, const char * argv[]) {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    int n;
    cin>>n;
    map<int,vector<int>> mp;
    map<int,int> mpy,mpx;
    vector<int>vx,vy;
    for(int i=0;i<n;i++){
        int x,y;
        cin>>x>>y;
        mp[y].push_back(x);
        if(mpx[x]==0){
            vx.push_back(x);
            mpx[x]=1;
        }
        if(mpy[y]==0){
            vy.push_back(y);
            mpy[y]=1;
        }
    }
    for(auto y: mp){
        sort(mp[y.first].begin(),mp[y.first].end());
    }
    int m=vx.size();
    sort(vx.begin(),vx.end());
    map<int,int> indx;
    for(int i=0;i<m;i++){
        indx[vx[i]]=i;
    }
    vector<int> treex(m+1);
    sort(vy.begin(),vy.end());
    reverse(vy.begin(),vy.end());
    int k=vy.size();
    ll ans=0;
    map<int,int> visx;
    for(int i=0;i<k;i++){
        int a=mp[vy[i]].size();
        int prevl=0,prevr=0,lastl=0,sub=0;
        for(int g=0;g<a;g++){
            if(visx[mp[vy[i]][g]]){
                    sub+=1;
                }
        }
        for(int j=0;j<a;j++){
            int x=mp[vy[i]][j];
            int ind=indx[x];
            if(visx[x]){
                sub-=1;
            }
            if(visx[x]==0){
                upd(ind+1,1,treex,m);
                visx[x]=1;
            }
            int left=sum(ind,treex,m);
            int right=sum(m,treex,m);
            int indl=j,indr=a-j-1-sub;
            int r=right-(left+1);
            ll add=(left+1-indl-lastl)*1LL*(r+1+indr);
            lastl=(left-indl);
            ans+=add;
        }
    }
    cout<<ans<<endl;
}


//
//  main.cpp
//  A
//
//  Created by E SAMEER KUMAR on 09/04/20.
//  Copyright © 2020 E SAMEER KUMAR. All rights reserved.

#include <bits/stdc++.h>
using ll = long long;
using namespace std;
//map<int,vector<int>> tree;
//map<int,vector<int>> rooted;
//map<int,int> primes;
void debugi(vector<int> & vec){
    int n=(int)vec.size();
    for(int i=0;i<n;i++){
        cout<<vec[i]<<" ";
    }
    cout<<endl;
}
void debugl(vector<ll> & vec){
    int n=(int)vec.size();
    for(int i=0;i<n;i++){
        cout<<vec[i]<<" ";
    }
    cout<<endl;
}
void debugmap(map<int,int> & mp){
    for(auto x:mp){
        cout<<x.first<<" "<<x.second<<" , ";
    }
    cout<<endl;
}
void debugset(set<int> & st){
    for(auto x: st){
        cout<<x<<" ";
    }
    cout<<endl;
}
void debugparri(vector<pair<int, int>>& arr){
    for(int i=0;i<(int)arr.size();i++){
        cout<<"["<<arr[i].first<<" : "<<arr[i].second<<"]"<<" ";
    }
    cout<<endl;
}
void debugpi(pair<int, int> &pi){
    cout<<pi.first<<" "<<pi.second<<endl;
}
void debugq(queue<int> q){
    while(!q.empty()){
        cout<<q.front()<<" ";
        q.pop();
    }
    cout<<endl;
}

bool check(int n,int i,int j){
    if((0<=i & i<n) && (0<=j & j<n)){
        return true;
    }
    return false;
}
ll MOD = 1e9+7;
ll powab(ll a,ll b,ll mod){
    if(b==0){
        return 1;
    }
    ll z=powab(a, b/2, mod);
    ll res=(z*z*1LL)%mod;
    if(b&1){
        res=(res*1LL*a)%mod;
    }
    return res;
}
//ll modinv(ll a){
//    ll ans=powab(a, mod-2, mod);
//    return ans;
//}
void upd(int k, int x,vector<int>& tree,int n){
//    cout<<k<<" k "<<endl;
    if(k==0){
        return;
    }
//    cout<<k<<" k "<<endl;
    while(k<=n){
//        cout<<k<<" kk "<<endl;
        tree[k]+=x;
        k+=(k&-k);
    }
}
int sum(int k,vector<int>& tree,int n){
    int s=0;
    while(k>=1){
        s+=tree[k];
        k-=(k&-k);
    }
    return s;
}
// char s[100006];
// int m=200005;
// int p;
//int mod(int x,int mod){
//    if(x<0){
//        return mod-(x%mod);
//    }
//    else{
//        return x%mod;
//    }
//}
ll gcd(ll a, ll b){
    if(b==0){
        return a;
    }
    return gcd(b,a%b);
}
// int ans=0,n,m;
int main(int argc, const char * argv[]) {
    // insert code here...
    // ofstream file;
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    int n;
    cin>>n;
    map<int,vector<int>> mp;
    map<int,int> mpy,mpx;
    vector<int>vx,vy;
    for(int i=0;i<n;i++){
        int x,y;
        cin>>x>>y;
        mp[y].push_back(x);
        if(mpx[x]==0){
            vx.push_back(x);
            mpx[x]=1;
        }
        if(mpy[y]==0){
            vy.push_back(y);
            mpy[y]=1;
        }
    }
    for(auto y: mp){
        sort(mp[y.first].begin(),mp[y.first].end());
    }
    int m=vx.size();
    sort(vx.begin(),vx.end());
    map<int,int> indx;
    for(int i=0;i<m;i++){
        indx[vx[i]]=i;
    }
    vector<int> treex(m+1);
    sort(vy.begin(),vy.end());
    reverse(vy.begin(),vy.end());
    int k=vy.size();
    ll ans=0;
    map<int,int> visx;
    for(int i=0;i<k;i++){
        int a=mp[vy[i]].size();
        // cout<<a<<" a "<<endl;
        for(int j=0;j<a;j++){
            int x=mp[vy[i]][j];
            int ind=indx[x];
            if(visx[x]==0){
                // int ind=indx[x];
                upd(ind+1,1,treex,m);
                visx[x]=1;
            }
            int sub=0;
            for(int g=j+1;g<a;g++){
                if(visx[mp[vy[i]][g]]){
                    sub+=1;
                }
            }
            int left=sum(ind,treex,m);
            int right=sum(m,treex,m);
            // cout<<left<<" leftt "<<right<<" rightt "<<endl;
            int indl=j,indr=a-j-1-sub;
            // cout<<indl<<" indl "<<indr<<" indr "<<endl;
            int r=right-(left+1);
            // debugi(treex);
            // cout<<left<<" left "<<right<<" right "<<x<<" x "<<ind<<" ind "<<endl;
            // cout<<left+1-indl<<" "<<r+1+indr<<" "<<x<<" x "<<vy[i]<<" y "<<endl;
            ll add=(left+1-indl)*1LL*(r+1+indr);
            ans+=add;
        }
    }
    cout<<ans<<endl;
    // for(int i=0;i<n;i++){
    //     int x,y;
    //     cin>>x>>y;
    //     mp[y].push_back(x);
    //     if(mpx[x]==0){
    //         vx.push_back(x);
    //         mpx[x]=1;
    //     }
    //     if(mpy[y]==0){
    //         vy.push_back(y);
    //         mpy[y]=1;
    //     }
    // }
    // for(auto x:mp){
    //     sort(mp[x].begin(),mp[x].end());
    // }
    // map<int,ll> cnty;
    // ll ans=0;
    // sort(vx.begin(),vx.end());
    // sort(vy.begin(),vy.end());
    // int m=vx.size(),k=vy.size();
    // for(int i=m-1;i>=0;i--){
    //     // int k=y.size();
    //     ll prev=0;
    //     for(auto y:mp[vx[i]]){
    //         cout<<vx[i]<<" vxi "<<y<<" y  "<<endl;
    //         cnty[y]+=1;
    //     }
    //     int a=mp[vx[i]].size();
    //     for(int j=a;j>=0;j--){
    //         int nxt=0;
    //         if(j-1>=0){
    //             nxt=mp[vx[i]][j-1];
    //         }
    //         for(int )
    //     }
    //     for(int j=k-1;j>=0;j--){
    //         prev+=cnty[vy[j]];
    //     }
    //     ans+=prev;
    // }
    // cout<<ans<<endl;
    // for(auto x:mp){
    //     sort(x.second.begin(),x.second.end());
    //     debugi(x.second);
    // }
    // ll ans=0;
    // for(auto i=mp.rbegin(); i!=mp.rend(); i++){
    //     int m=i->second.size();
    //     cout<<m<<" m "<<endl;
    //     mpx[i->first]+=1;
    //     // mpy[y.first]+=1;
    //     for(int j=m-1;j>=0;j--){
    //         cout<<j<<" j "<<endl;
    //         mpy[i->second[j]]+=1;

    //         if(j-1>=0){
    //             last=
    //         }
    //         for(auto y:mpy){

    //             cout<<y.first<<" y "<<endl;
    //             ans+=mpy[y.first];
    //         }
    //     }

    // }
    // cout<<ans<<endl;
}


//
//  main.cpp
//  A
//
//  Created by E SAMEER KUMAR on 09/04/20.
//  Copyright © 2020 E SAMEER KUMAR. All rights reserved.

#include <bits/stdc++.h>
using ll = long long;
using namespace std;
//map<int,vector<int>> tree;
//map<int,vector<int>> rooted;
//map<int,int> primes;
void debugi(vector<int> & vec){
    int n=(int)vec.size();
    for(int i=0;i<n;i++){
        cout<<vec[i]<<" ";
    }
    cout<<endl;
}
void debugl(vector<ll> & vec){
    int n=(int)vec.size();
    for(int i=0;i<n;i++){
        cout<<vec[i]<<" ";
    }
    cout<<endl;
}
void debugmap(map<int,int> & mp){
    for(auto x:mp){
        cout<<x.first<<" "<<x.second<<" , ";
    }
    cout<<endl;
}
void debugset(set<int> & st){
    for(auto x: st){
        cout<<x<<" ";
    }
    cout<<endl;
}
void debugparri(vector<pair<int, int>>& arr){
    for(int i=0;i<(int)arr.size();i++){
        cout<<"["<<arr[i].first<<" : "<<arr[i].second<<"]"<<" ";
    }
    cout<<endl;
}
void debugpi(pair<int, int> &pi){
    cout<<pi.first<<" "<<pi.second<<endl;
}
void debugq(queue<int> q){
    while(!q.empty()){
        cout<<q.front()<<" ";
        q.pop();
    }
    cout<<endl;
}

bool check(int n,int i,int j){
    if((0<=i & i<n) && (0<=j & j<n)){
        return true;
    }
    return false;
}
ll MOD = 1e9+7;
ll powab(ll a,ll b,ll mod){
    if(b==0){
        return 1;
    }
    ll z=powab(a, b/2, mod);
    ll res=(z*z*1LL)%mod;
    if(b&1){
        res=(res*1LL*a)%mod;
    }
    return res;
}
//ll modinv(ll a){
//    ll ans=powab(a, mod-2, mod);
//    return ans;
//}
void upd(int k, int x,vector<int>& tree,int n){
//    cout<<k<<" k "<<endl;
    if(k==0){
        return;
    }
//    cout<<k<<" k "<<endl;
    while(k<=n){
//        cout<<k<<" kk "<<endl;
        tree[k]+=x;
        k+=(k&-k);
    }
}
int sum(int k,vector<int>& tree,int n){
    int s=0;
    while(k>=1){
        s+=tree[k];
        k-=(k&-k);
    }
    return s;
}
// char s[100006];
// int m=200005;
// int p;
//int mod(int x,int mod){
//    if(x<0){
//        return mod-(x%mod);
//    }
//    else{
//        return x%mod;
//    }
//}
ll gcd(ll a, ll b){
    if(b==0){
        return a;
    }
    return gcd(b,a%b);
}
// int ans=0,n,m;
int main(int argc, const char * argv[]) {
    // insert code here...
    // ofstream file;
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    int n;
    cin>>n;
    map<int,vector<int>> mp;
    map<int,int> mpy,mpx;
    vector<int>vx,vy;
    for(int i=0;i<n;i++){
        int x,y;
        cin>>x>>y;
        mp[y].push_back(x);
        if(mpx[x]==0){
            vx.push_back(x);
            mpx[x]=1;
        }
        if(mpy[y]==0){
            vy.push_back(y);
            mpy[y]=1;
        }
    }
    for(auto y: mp){
        sort(mp[y.first].begin(),mp[y.first].end());
    }
    int m=vx.size();
    sort(vx.begin(),vx.end());
    map<int,int> indx;
    for(int i=0;i<m;i++){
        indx[vx[i]]=i;
    }
    vector<int> treex(m+1);
    sort(vy.begin(),vy.end());
    reverse(vy.begin(),vy.end());
    int k=vy.size();
    ll ans=0;
    map<int,int> visx;
    for(int i=0;i<k;i++){
        int a=mp[vy[i]].size();
        // cout<<a<<" a "<<endl;
        int prevl=0,prevr=0,lastl=0;
        for(int j=0;j<a;j++){
            int x=mp[vy[i]][j];
            int ind=indx[x];
            if(visx[x]==0){
                // int ind=indx[x];
                upd(ind+1,1,treex,m);
                visx[x]=1;
            }
            int sub=0;
            for(int g=j+1;g<a;g++){
                if(visx[mp[vy[i]][g]]){
                    sub+=1;
                }
            }
            int left=sum(ind,treex,m);
            int right=sum(m,treex,m);
            // cout<<left<<" leftt "<<right<<" rightt "<<endl;
            int indl=j,indr=a-j-1-sub;
            // cout<<indl<<" indl "<<indr<<" indr "<<endl;
            int r=right-(left+1);
            // debugi(treex);
            // cout<<left<<" left "<<right<<" right "<<x<<" x "<<ind<<" ind "<<endl;
            // cout<<left+1-indl<<" "<<r+1+indr<<" "<<x<<" x "<<vy[i]<<" y "<<lastl<<" lastl "<<endl;
            // ll add=(left-indl+r+indr+1;
            // cout<<lastl<<" lastl "<<
            ll add=(left+1-indl-lastl)*1LL*(r+1+indr);
            lastl=(left-indl);
            // prevl=left+1-indl;prevr=r+1+indr;
            // left+=1;
            // ll add=(left+1)*1LL;
            ans+=add;
        }
    }
    cout<<ans<<endl;
    // for(int i=0;i<n;i++){
    //     int x,y;
    //     cin>>x>>y;
    //     mp[y].push_back(x);
    //     if(mpx[x]==0){
    //         vx.push_back(x);
    //         mpx[x]=1;
    //     }
    //     if(mpy[y]==0){
    //         vy.push_back(y);
    //         mpy[y]=1;
    //     }
    // }
    // for(auto x:mp){
    //     sort(mp[x].begin(),mp[x].end());
    // }
    // map<int,ll> cnty;
    // ll ans=0;
    // sort(vx.begin(),vx.end());
    // sort(vy.begin(),vy.end());
    // int m=vx.size(),k=vy.size();
    // for(int i=m-1;i>=0;i--){
    //     // int k=y.size();
    //     ll prev=0;
    //     for(auto y:mp[vx[i]]){
    //         cout<<vx[i]<<" vxi "<<y<<" y  "<<endl;
    //         cnty[y]+=1;
    //     }
    //     int a=mp[vx[i]].size();
    //     for(int j=a;j>=0;j--){
    //         int nxt=0;
    //         if(j-1>=0){
    //             nxt=mp[vx[i]][j-1];
    //         }
    //         for(int )
    //     }
    //     for(int j=k-1;j>=0;j--){
    //         prev+=cnty[vy[j]];
    //     }
    //     ans+=prev;
    // }
    // cout<<ans<<endl;
    // for(auto x:mp){
    //     sort(x.second.begin(),x.second.end());
    //     debugi(x.second);
    // }
    // ll ans=0;
    // for(auto i=mp.rbegin(); i!=mp.rend(); i++){
    //     int m=i->second.size();
    //     cout<<m<<" m "<<endl;
    //     mpx[i->first]+=1;
    //     // mpy[y.first]+=1;
    //     for(int j=m-1;j>=0;j--){
    //         cout<<j<<" j "<<endl;
    //         mpy[i->second[j]]+=1;

    //         if(j-1>=0){
    //             last=
    //         }
    //         for(auto y:mpy){

    //             cout<<y.first<<" y "<<endl;
    //             ans+=mpy[y.first];
    //         }
    //     }

    // }
    // cout<<ans<<endl;
}


//
//  main.cpp
//  A
//
//  Created by E SAMEER KUMAR on 09/04/20.
//  Copyright © 2020 E SAMEER KUMAR. All rights reserved.

#include <bits/stdc++.h>
using ll = long long;
using namespace std;
//map<int,vector<int>> tree;
//map<int,vector<int>> rooted;
//map<int,int> primes;
void debugi(vector<int> & vec){
    int n=(int)vec.size();
    for(int i=0;i<n;i++){
        cout<<vec[i]<<" ";
    }
    cout<<endl;
}
void debugl(vector<ll> & vec){
    int n=(int)vec.size();
    for(int i=0;i<n;i++){
        cout<<vec[i]<<" ";
    }
    cout<<endl;
}
void debugmap(map<int,int> & mp){
    for(auto x:mp){
        cout<<x.first<<" "<<x.second<<" , ";
    }
    cout<<endl;
}
void debugset(set<int> & st){
    for(auto x: st){
        cout<<x<<" ";
    }
    cout<<endl;
}
void debugparri(vector<pair<int, int>>& arr){
    for(int i=0;i<(int)arr.size();i++){
        cout<<"["<<arr[i].first<<" : "<<arr[i].second<<"]"<<" ";
    }
    cout<<endl;
}
void debugpi(pair<int, int> &pi){
    cout<<pi.first<<" "<<pi.second<<endl;
}
void debugq(queue<int> q){
    while(!q.empty()){
        cout<<q.front()<<" ";
        q.pop();
    }
    cout<<endl;
}

bool check(int n,int i,int j){
    if((0<=i & i<n) && (0<=j & j<n)){
        return true;
    }
    return false;
}
ll MOD = 1e9+7;
ll powab(ll a,ll b,ll mod){
    if(b==0){
        return 1;
    }
    ll z=powab(a, b/2, mod);
    ll res=(z*z*1LL)%mod;
    if(b&1){
        res=(res*1LL*a)%mod;
    }
    return res;
}
//ll modinv(ll a){
//    ll ans=powab(a, mod-2, mod);
//    return ans;
//}
void upd(int k, int x,vector<int>& tree,int n){
//    cout<<k<<" k "<<endl;
    if(k==0){
        return;
    }
//    cout<<k<<" k "<<endl;
    while(k<=n){
//        cout<<k<<" kk "<<endl;
        tree[k]+=x;
        k+=(k&-k);
    }
}
int sum(int k,vector<int>& tree,int n){
    int s=0;
    while(k>=1){
        s+=tree[k];
        k-=(k&-k);
    }
    return s;
}
// char s[100006];
// int m=200005;
// int p;
//int mod(int x,int mod){
//    if(x<0){
//        return mod-(x%mod);
//    }
//    else{
//        return x%mod;
//    }
//}
ll gcd(ll a, ll b){
    if(b==0){
        return a;
    }
    return gcd(b,a%b);
}
// int ans=0,n,m;
int main(int argc, const char * argv[]) {
    // insert code here...
    // ofstream file;
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    int n;
    cin>>n;
    map<int,vector<int>> mp;
    map<int,int> mpy,mpx;
    vector<int>vx,vy;
    for(int i=0;i<n;i++){
        int x,y;
        cin>>x>>y;
        mp[x].push_back(y);
        if(mpx[x]==0){
            vx.push_back(x);
            mpx[x]=1;
        }
        if(mpy[y]==0){
            vy.push_back(y);
            mpy[y]=1;
        }
    }
    map<int,ll> cnty;
    ll ans=0;
    sort(vx.begin(),vx.end());
    sort(vy.begin(),vy.end());
    int m=vx.size(),k=vy.size();
    for(int i=m-1;i>=0;i--){
        // int k=y.size();
        ll prev=0;
        for(auto y:mp[vx[i]]){
            cnty[y]+=1;
        }
        for(int j=k-1;j>=0;j--){
            prev+=cnty[vy[j]];
        }
        ans+=prev;
    }
    cout<<ans<<endl;
    // for(auto x:mp){
    //     sort(x.second.begin(),x.second.end());
    //     debugi(x.second);
    // }
    // ll ans=0;
    // for(auto i=mp.rbegin(); i!=mp.rend(); i++){
    //     int m=i->second.size();
    //     cout<<m<<" m "<<endl;
    //     mpx[i->first]+=1;
    //     // mpy[y.first]+=1;
    //     for(int j=m-1;j>=0;j--){
    //         cout<<j<<" j "<<endl;
    //         mpy[i->second[j]]+=1;

    //         if(j-1>=0){
    //             last=
    //         }
    //         for(auto y:mpy){

    //             cout<<y.first<<" y "<<endl;
    //             ans+=mpy[y.first];
    //         }
    //     }

    // }
    // cout<<ans<<endl;
}


#include<bits/stdc++.h>
using namespace std;
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define test int t;cin>>t;while(t--)
#define all(x) x.begin(),x.end()
#define setp(x) fixed<<setprecision(x)
#define Pi 3.14159265358979323846264338
#define fore(i, l, r) for(int i = int(l); i < int(r); i++)
#define forn(i, n) fore(i, 0, n)
#define forr(n, i) for(int i=int(n-1);i>=0;i--)
#define mp make_pair
#define pb push_back
#define pi pair<ll,ll>
#define pii pair<ll,pair<ll,ll> >
#define ff first
#define ss second
#define maxn 400001
typedef long long int ll;
typedef vector<vector<ll> > mat;
//********************* mat *********************
/* mat matMul(mat A,mat B,ll m)
{int r1=A.size(),r2=B.size(),c1=A[0].size(),c2=B[0].size();mat ans(r1);for(int i=0;i<r1;i++)
for(int j=0;j<c2;j++)
{ll mul=0;for(int k=0;k<c1;k++)
mul=(mul+A[i][k]*B[k][j])%m;ans[i].pb(mul);}
return ans;}
mat matPow(mat x,ll n,ll m)
{int r=x.size(),c=x[0].size();mat result(r);forn(i,r)
forn(j,c)
{if(i==j)
result[i].pb(1);else
result[i].pb(0);}
while(n>0)
{if(n%2==1)
result=matMul(result,x,m);x=matMul(x,x,m);n=n/2;}
return result;}  */
//******************** mat **********************
ll mod=1e9+7;
const ll Size=3e6+1;
int minPrime[Size];
vector<pair<int,int> > factor[Size];
void findPrime() { for(int i=1;i<=Size;i++) minPrime[i]=i;
	for(ll i=2;i<Size;i++){ if(minPrime[i]!=i) continue; for(ll j=i*i;j<Size;j+=i){ if(minPrime[j]==j) minPrime[j]=i; } }
	for(int i=2;i<Size;i++){ int x=i; while(x>1) { int p=minPrime[x]; int c=0; while(x%p==0) { c++; x/=p; } factor[i].pb(mp(p,c)); } } }
ll factorial[Size];
ll pow1(ll x,ll n,ll m)  {  ll result=1; while(n>0) {  x%=m; if(n % 2 ==1) result=(result * x)%m; x=(x*x)%m; n=n/2; } return result; }
ll pow2(ll x,ll n)  {  ll result=1; while(n>0) {   if(n % 2 ==1) result=(result * x); x=(x*x); n=n/2; } return result; }
ll modInverse(ll A,ll M) { return pow1(A,M-2,M); }
void fact() { factorial[0]=factorial[1]=1; for(int i=2;i<Size;i++) factorial[i]=(factorial[i-1]*i)%mod;}
//ll ncr(ll n,ll r){ if(n<=0 or r<=0) return 1; ll x=(factorial[r]*factorial[n-r])%mod; x=(factorial[n]*modInverse(x,mod))%mod;return x; }
//ll gcd(ll a,ll b) { if(b==0) return a; else return gcd(b,a%b); }
//------------------------------------------------------------------------------------------------------------------------------------//

map<ll,vector<ll> > Adj;
int n;
map<ll ,int> cord;

int BIT[Size];
bool up[Size];
void update(int i,int val)
{
	for(;i<Size;i+=i&(-i))
	BIT[i]+=val;
}
int query(int i)
{
	int s=0;
	for(;i>0;i-=i&(-i))
	s+=BIT[i];
	return s;
}

void solve(){
	cin>>n;
	set<int> comp;
	forn(i,n)
	{
		ll x,y; cin>>x>>y;
		Adj[y].pb(x);
		comp.insert(x);
	}
	int c=1;
	for(auto e: comp)
	{
		cord[e]=c;
		c++;
	}
	ll ans=0;
	for(auto e : Adj )
	{
		vector<ll> v=e.ss;
		for(auto f : v)
		{
			if(up[f])continue;
			update(cord[f],1);
			up[f]=1;
		}
		ll T=query(Size-10);
		//cout<<e.ff<<" "<<T<<" ";
		T++;
		T=T*(T-1); T/=2;
		//cout<<T<<"\n";
		ll sub=0;
		sort(all(v));
		for(int i=0;i<v.size();i++)
		{
			ll cur=0;
			if(i==0)
			{
				cur=query(cord[v[i]]-1);
				cur++;
				cur=cur*(cur-1);
				cur/=2;
			}
			else if(i==v.size()-1)
			{
				cur=query(Size-10)-query(cord[v[i]]);
				cur++;
				cur=cur*(cur-1);
				cur/=2;
			}
			else
			{
				cur=query(cord[v[i]]-1)-query(cord[v[i-1]]);
				cur++;
				cur=cur*(cur-1);
				cur/=2;
			}
			sub+=cur;
			//cout<<v[i]<<" "<<cur<<"\n";

		}
		ans+=(T-sub);
	}
	cout<<ans;
}

int main()
{
	fast;
	int t=1;
	//cin>>t;
	while(t--){
		solve();
	}
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define test int t;cin>>t;while(t--)
#define all(x) x.begin(),x.end()
#define setp(x) fixed<<setprecision(x)
#define Pi 3.14159265358979323846264338
#define fore(i, l, r) for(int i = int(l); i < int(r); i++)
#define forn(i, n) fore(i, 0, n)
#define forr(n, i) for(int i=int(n-1);i>=0;i--)
#define mp make_pair
#define pb push_back
#define pi pair<ll,ll>
#define pii pair<ll,pair<ll,ll> >
#define ff first
#define ss second
#define maxn 400001
typedef long long int ll;
typedef vector<vector<ll> > mat;
//********************* mat *********************
/* mat matMul(mat A,mat B,ll m)
{int r1=A.size(),r2=B.size(),c1=A[0].size(),c2=B[0].size();mat ans(r1);for(int i=0;i<r1;i++)
for(int j=0;j<c2;j++)
{ll mul=0;for(int k=0;k<c1;k++)
mul=(mul+A[i][k]*B[k][j])%m;ans[i].pb(mul);}
return ans;}
mat matPow(mat x,ll n,ll m)
{int r=x.size(),c=x[0].size();mat result(r);forn(i,r)
forn(j,c)
{if(i==j)
result[i].pb(1);else
result[i].pb(0);}
while(n>0)
{if(n%2==1)
result=matMul(result,x,m);x=matMul(x,x,m);n=n/2;}
return result;}  */
//******************** mat **********************
ll mod=1e9+7;
const ll Size=3e6+1;
int minPrime[Size];
vector<pair<int,int> > factor[Size];
void findPrime() { for(int i=1;i<=Size;i++) minPrime[i]=i;
	for(ll i=2;i<Size;i++){ if(minPrime[i]!=i) continue; for(ll j=i*i;j<Size;j+=i){ if(minPrime[j]==j) minPrime[j]=i; } }
	for(int i=2;i<Size;i++){ int x=i; while(x>1) { int p=minPrime[x]; int c=0; while(x%p==0) { c++; x/=p; } factor[i].pb(mp(p,c)); } } }
ll factorial[Size];
ll pow1(ll x,ll n,ll m)  {  ll result=1; while(n>0) {  x%=m; if(n % 2 ==1) result=(result * x)%m; x=(x*x)%m; n=n/2; } return result; }
ll pow2(ll x,ll n)  {  ll result=1; while(n>0) {   if(n % 2 ==1) result=(result * x); x=(x*x); n=n/2; } return result; }
ll modInverse(ll A,ll M) { return pow1(A,M-2,M); }
void fact() { factorial[0]=factorial[1]=1; for(int i=2;i<Size;i++) factorial[i]=(factorial[i-1]*i)%mod;}
//ll ncr(ll n,ll r){ if(n<=0 or r<=0) return 1; ll x=(factorial[r]*factorial[n-r])%mod; x=(factorial[n]*modInverse(x,mod))%mod;return x; }
//ll gcd(ll a,ll b) { if(b==0) return a; else return gcd(b,a%b); }
//------------------------------------------------------------------------------------------------------------------------------------//

map<ll,vector<ll> > Adj;
int n;
map<ll ,int> cord;

int BIT[Size];
bool up[Size];
void update(int i,int val)
{
	for(;i<Size;i+=i&(-i))
	BIT[i]+=val;
}
int query(int i)
{
	int s=0;
	for(;i>0;i-=i&(-i))
	s+=BIT[i];
	return s;
}

void solve(){
	cin>>n;
	set<int> comp;
	forn(i,n)
	{
		ll x,y; cin>>x>>y;
		Adj[-y].pb(x);
		comp.insert(x);
	}
	int c=1;
	for(auto e: comp)
	{
		cord[e]=c;
		c++;
	}
	ll ans=0;
	for(auto e : Adj )
	{
		vector<ll> v=e.ss;
		for(auto f : v)
		{
			if(up[cord[f]])continue;
			update(cord[f],1);
			up[cord[f]]=1;
		}
		ll T=query(Size-10);
		//cout<<e.ff<<" "<<T<<" ";
		T++;
		T=T*(T-1); T/=2;
		//cout<<T<<"\n";
		ll sub=0;
		sort(all(v));
		for(int i=0;i<v.size();i++)
		{
			ll cur=0,temp=0;;
			if(i==0)
			{
				cur=query(cord[v[i]]-1);
				cur++;
				cur=cur*(cur-1);
				cur/=2;
				temp+=cur;
			}
			if(i==v.size()-1)
			{
				cur=query(Size-10)-query(cord[v[i]]);
				cur++;
				cur=cur*(cur-1);
				cur/=2;
				temp+=cur;
			}
			if(i>0 )
			{
				cur=query(cord[v[i]]-1)-query(cord[v[i-1]]);
				cur++;
				cur=cur*(cur-1);
				cur/=2;
				temp+=cur;
			}
			sub+=temp;
			//cout<<v[i]<<" "<<temp<<"\n";

		}
		ans+=(T-sub);
	}
	cout<<ans;
}

int main()
{
	fast;
	int t=1;
	//cin>>t;
	while(t--){
		solve();
	}
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define test int t;cin>>t;while(t--)
#define all(x) x.begin(),x.end()
#define setp(x) fixed<<setprecision(x)
#define Pi 3.14159265358979323846264338
#define fore(i, l, r) for(int i = int(l); i < int(r); i++)
#define forn(i, n) fore(i, 0, n)
#define forr(n, i) for(int i=int(n-1);i>=0;i--)
#define mp make_pair
#define pb push_back
#define pi pair<ll,ll>
#define pii pair<ll,pair<ll,ll> >
#define ff first
#define ss second
#define maxn 400001
typedef long long int ll;
typedef vector<vector<ll> > mat;
//********************* mat *********************
/* mat matMul(mat A,mat B,ll m)
{int r1=A.size(),r2=B.size(),c1=A[0].size(),c2=B[0].size();mat ans(r1);for(int i=0;i<r1;i++)
for(int j=0;j<c2;j++)
{ll mul=0;for(int k=0;k<c1;k++)
mul=(mul+A[i][k]*B[k][j])%m;ans[i].pb(mul);}
return ans;}
mat matPow(mat x,ll n,ll m)
{int r=x.size(),c=x[0].size();mat result(r);forn(i,r)
forn(j,c)
{if(i==j)
result[i].pb(1);else
result[i].pb(0);}
while(n>0)
{if(n%2==1)
result=matMul(result,x,m);x=matMul(x,x,m);n=n/2;}
return result;}  */
//******************** mat **********************
ll mod=1e9+7;
const ll Size=3e6+1;
int minPrime[Size];
vector<pair<int,int> > factor[Size];
void findPrime() { for(int i=1;i<=Size;i++) minPrime[i]=i;
	for(ll i=2;i<Size;i++){ if(minPrime[i]!=i) continue; for(ll j=i*i;j<Size;j+=i){ if(minPrime[j]==j) minPrime[j]=i; } }
	for(int i=2;i<Size;i++){ int x=i; while(x>1) { int p=minPrime[x]; int c=0; while(x%p==0) { c++; x/=p; } factor[i].pb(mp(p,c)); } } }
ll factorial[Size];
ll pow1(ll x,ll n,ll m)  {  ll result=1; while(n>0) {  x%=m; if(n % 2 ==1) result=(result * x)%m; x=(x*x)%m; n=n/2; } return result; }
ll pow2(ll x,ll n)  {  ll result=1; while(n>0) {   if(n % 2 ==1) result=(result * x); x=(x*x); n=n/2; } return result; }
ll modInverse(ll A,ll M) { return pow1(A,M-2,M); }
void fact() { factorial[0]=factorial[1]=1; for(int i=2;i<Size;i++) factorial[i]=(factorial[i-1]*i)%mod;}
//ll ncr(ll n,ll r){ if(n<=0 or r<=0) return 1; ll x=(factorial[r]*factorial[n-r])%mod; x=(factorial[n]*modInverse(x,mod))%mod;return x; }
//ll gcd(ll a,ll b) { if(b==0) return a; else return gcd(b,a%b); }
//------------------------------------------------------------------------------------------------------------------------------------//

map<ll,vector<ll> > Adj;
int n;
map<ll ,int> cord;

int BIT[Size];
bool up[Size];
void update(int i,int val)
{
	for(;i<Size;i+=i&(-i))
	BIT[i]+=val;
}
int query(int i)
{
	int s=0;
	for(;i>0;i-=i&(-i))
	s+=BIT[i];
	return s;
}

void solve(){
	cin>>n;
	set<int> comp;
	forn(i,n)
	{
		ll x,y; cin>>x>>y;
		Adj[-y].pb(x);
		comp.insert(x);
	}
	int c=1;
	for(auto e: comp)
	{
		cord[e]=c;
		c++;
	}
	ll ans=0;
	for(auto e : Adj )
	{
		vector<ll> v=e.ss;
		for(auto f : v)
		{
			if(up[cord[f]])continue;
			update(cord[f],1);
			up[cord[f]]=1;
		}
		ll T=query(Size-10);
		//cout<<e.ff<<" "<<T<<" ";
		T++;
		T=T*(T-1); T/=2;
		//cout<<T<<"\n";
		ll sub=0;
		sort(all(v));
		for(int i=0;i<v.size();i++)
		{
			ll cur=0,temp=0;;
			if(i==0)
			{
				cur=query(cord[v[i]]-1);
				cur++;
				cur=cur*(cur-1);
				cur/=2;
				temp+=cur;
			}
			if(i==v.size()-1)
			{
				cur=query(Size-10)-query(cord[v[i]]);
				cur++;
				cur=cur*(cur-1);
				cur/=2;
				temp+=cur;
			}
			if(i>0 and i<v.size()-1)
			{
				cur=query(cord[v[i]]-1)-query(cord[v[i-1]]);
				cur++;
				cur=cur*(cur-1);
				cur/=2;
				temp+=cur;
			}
			sub+=temp;
			//cout<<v[i]<<" "<<temp<<"\n";

		}
		ans+=(T-sub);
	}
	cout<<ans;
}

int main()
{
	fast;
	int t=1;
	//cin>>t;
	while(t--){
		solve();
	}
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define test int t;cin>>t;while(t--)
#define all(x) x.begin(),x.end()
#define setp(x) fixed<<setprecision(x)
#define Pi 3.14159265358979323846264338
#define fore(i, l, r) for(int i = int(l); i < int(r); i++)
#define forn(i, n) fore(i, 0, n)
#define forr(n, i) for(int i=int(n-1);i>=0;i--)
#define mp make_pair
#define pb push_back
#define pi pair<ll,ll>
#define pii pair<ll,pair<ll,ll> >
#define ff first
#define ss second
#define maxn 400001
typedef long long int ll;
typedef vector<vector<ll> > mat;
//********************* mat *********************
/* mat matMul(mat A,mat B,ll m)
{int r1=A.size(),r2=B.size(),c1=A[0].size(),c2=B[0].size();mat ans(r1);for(int i=0;i<r1;i++)
for(int j=0;j<c2;j++)
{ll mul=0;for(int k=0;k<c1;k++)
mul=(mul+A[i][k]*B[k][j])%m;ans[i].pb(mul);}
return ans;}
mat matPow(mat x,ll n,ll m)
{int r=x.size(),c=x[0].size();mat result(r);forn(i,r)
forn(j,c)
{if(i==j)
result[i].pb(1);else
result[i].pb(0);}
while(n>0)
{if(n%2==1)
result=matMul(result,x,m);x=matMul(x,x,m);n=n/2;}
return result;}  */
//******************** mat **********************
ll mod=1e9+7;
const ll Size=3e6+1;
int minPrime[Size];
vector<pair<int,int> > factor[Size];
void findPrime() { for(int i=1;i<=Size;i++) minPrime[i]=i;
	for(ll i=2;i<Size;i++){ if(minPrime[i]!=i) continue; for(ll j=i*i;j<Size;j+=i){ if(minPrime[j]==j) minPrime[j]=i; } }
	for(int i=2;i<Size;i++){ int x=i; while(x>1) { int p=minPrime[x]; int c=0; while(x%p==0) { c++; x/=p; } factor[i].pb(mp(p,c)); } } }
ll factorial[Size];
ll pow1(ll x,ll n,ll m)  {  ll result=1; while(n>0) {  x%=m; if(n % 2 ==1) result=(result * x)%m; x=(x*x)%m; n=n/2; } return result; }
ll pow2(ll x,ll n)  {  ll result=1; while(n>0) {   if(n % 2 ==1) result=(result * x); x=(x*x); n=n/2; } return result; }
ll modInverse(ll A,ll M) { return pow1(A,M-2,M); }
void fact() { factorial[0]=factorial[1]=1; for(int i=2;i<Size;i++) factorial[i]=(factorial[i-1]*i)%mod;}
//ll ncr(ll n,ll r){ if(n<=0 or r<=0) return 1; ll x=(factorial[r]*factorial[n-r])%mod; x=(factorial[n]*modInverse(x,mod))%mod;return x; }
//ll gcd(ll a,ll b) { if(b==0) return a; else return gcd(b,a%b); }
//------------------------------------------------------------------------------------------------------------------------------------//

map<ll,vector<ll> > Adj;
int n;
map<ll ,int> cord;

int BIT[Size];
bool up[Size];
void update(int i,int val)
{
	for(;i<Size;i+=i&(-i))
	BIT[i]+=val;
}
int query(int i)
{
	int s=0;
	for(;i>0;i-=i&(-i))
	s+=BIT[i];
	return s;
}

void solve(){
	cin>>n;
	set<int> comp;
	forn(i,n)
	{
		ll x,y; cin>>x>>y;
		Adj[y].pb(x);
		comp.insert(x);
	}
	int c=1;
	for(auto e: comp)
	{
		cord[e]=c;
		c++;
	}
	ll ans=0;
	for(auto e : Adj )
	{
		vector<ll> v=e.ss;
		for(auto f : v)
		{
			if(up[cord[f]])continue;
			update(cord[f],1);
			up[cord[f]]=1;
		}
		ll T=query(Size-10);
		//cout<<e.ff<<" "<<T<<" ";
		T++;
		T=T*(T-1); T/=2;
		//cout<<T<<"\n";
		ll sub=0;
		sort(all(v));
		for(int i=0;i<v.size();i++)
		{
			ll cur=0;
			if(i==0)
			{
				cur=query(cord[v[i]]-1);
				cur++;
				cur=cur*(cur-1);
				cur/=2;
			}
			else if(i==v.size()-1)
			{
				cur=query(Size-10)-query(cord[v[i]]);
				cur++;
				cur=cur*(cur-1);
				cur/=2;
			}
			else
			{
				cur=query(cord[v[i]]-1)-query(cord[v[i-1]]);
				cur++;
				cur=cur*(cur-1);
				cur/=2;
			}
			sub+=cur;
			//cout<<v[i]<<" "<<cur<<"\n";

		}
		ans+=(T-sub);
	}
	cout<<ans;
}

int main()
{
	fast;
	int t=1;
	//cin>>t;
	while(t--){
		solve();
	}
	return 0;
}


/* LittleFall : Hello! */
#include <bits/stdc++.h>
using namespace std; using ll = long long; inline int read();
const int M = 200016, MOD = 1000000007;

struct Discretization
{
	map<int,int> mp;
	void add(int n) {mp[n];}
	void solve()
	{
		int k = 1;
		for(auto &p : mp)
			p.second = k++;
	}
	int get(int v)
	{
		return mp[v];
	}
}dctx, dcty;
pair<int,int> save[M];
vector<int> tuosh[M]; //tuosh[i] 表示y=i时所有的x，排序
struct BinaryIndexTree
{
	int n;
	int c[M];
	void add(int p, int x)
	{
		for(; p<=n; p+=p&-p)
			c[p] += x;
	}
	int sum(int p)
	{
		int res = 0;
		for(; p; p-=p&-p)
			res += c[p];
		return res;
	}
	int sum(int l, int r)
	{
		return sum(r) - sum(l-1);
	}
}bit;
int main(void)
{
	#ifdef _LITTLEFALL_
	freopen("in.txt","r",stdin);
    #endif

	int n = read();
	for(int i=1; i<=n; ++i)
	{
		save[i].first = read(); dctx.add(save[i].first);
		save[i].second = read(); dcty.add(save[i].second);
	}
	dctx.solve(); dcty.solve();
	for(int i=1; i<=n; ++i)
	{
		save[i].first = dctx.get(save[i].first);
		save[i].second = dcty.get(save[i].second);
	}
	sort(save+1, save+n+1, [](const pair<int,int> &a, const pair<int,int> &b){
		return a.first<b.first;
	});
	for(int i=1; i<=n; ++i)
	{
		tuosh[save[i].second].push_back(save[i].first);
	}

	bit.n = n;
	ll ans = 0;
	for(int y=n; y>=1; --y)
	{
		for(int x : tuosh[y])
		{
			if(bit.sum(x,x)==0)
				bit.add(x,1);
		}
		int lst = 0;
		for(int x : tuosh[y])
		{
			ans += 1ll * bit.sum(lst+1, x) * bit.sum(x, n);
			lst = x;
		}
	}
	cout << ans << endl;

    return 0;
}

inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}