Monocarp is the coach of the Berland State University programming teams. He decided to compose a problemset for a training session for his teams.

Monocarp has $n$ problems that none of his students have seen yet. The $i$-th problem has a topic $a_i$ (an integer from $1$ to $n$) and a difficulty $b_i$ (an integer from $1$ to $n$). All problems are different, that is, there are no two tasks that have the same topic and difficulty at the same time.

Monocarp decided to select exactly $3$ problems from $n$ problems for the problemset. The problems should satisfy at least one of two conditions (possibly, both):

the topics of all three selected problems are different;

the difficulties of all three selected problems are different.

Your task is to determine the number of ways to select three problems for the problemset.


-----Input-----

The first line contains a single integer $t$ ($1 \le t \le 50000$) — the number of testcases.

The first line of each testcase contains an integer $n$ ($3 \le n \le 2 \cdot 10^5$) — the number of problems that Monocarp have.

In the $i$-th of the following $n$ lines, there are two integers $a_i$ and $b_i$ ($1 \le a_i, b_i \le n$) — the topic and the difficulty of the $i$-th problem.

It is guaranteed that there are no two problems that have the same topic and difficulty at the same time.

The sum of $n$ over all testcases doesn't exceed $2 \cdot 10^5$.


-----Output-----

Print the number of ways to select three training problems that meet either of the requirements described in the statement.


-----Examples-----

Input
2
4
2 4
3 4
2 1
1 3
5
1 5
2 4
3 3
4 2
5 1
Output
3
10


-----Note-----

In the first example, you can take the following sets of three problems:

problems $1$, $2$, $4$;

problems $1$, $3$, $4$;

problems $2$, $3$, $4$.

Thus, the number of ways is equal to three.

Source: codeforces | Difficulty: MEDIUM_HARD
Tags: Geometry

Combinatorics

Implementation

Mathematics

Data structures


Solutions:
t = int(input())
for _ in range(t):
	n = int(input())
	(a, b) = ([], [])
	c = dict()
	d = dict()
	for i in range(n):
		(x, y) = [int(i) for i in input().split()]
		a.append(x)
		b.append(y)
		c[x] = c.get(x, 0) + 1
		d[y] = d.get(y, 0) + 1
	ans = 0
	n1 = n
	for i in range(n):
		ans += (n1 - 2) * (n1 - 1) / 2 - (c[a[i]] - 1) * (d[b[i]] - 1)
		n1 -= 1
	print(int(ans))


import sys
input = sys.stdin.readline
from collections import Counter

def il():
	return list(map(int, input().split()))

def ii():
	return int(input())

def imi():
	return map(int, input().split())

def ist():
	return input()
T = ii()
for _ in range(T):
	n = ii()
	li = []
	t = Counter([])
	d = Counter([])
	for i in range(n):
		(a, b) = imi()
		t[a] += 1
		d[b] += 1
		li.append((a, b))
	N = n
	s = 0
	for i in li:
		(a, b) = i
		s += (t[a] - 1) * (d[b] - 1)
	ans = n * (n - 1) * (n - 2) // 6 - s
	print(ans)


from collections import Counter

def solve():
	n = int(input())
	tuples = [list(map(int, input().split())) for _ in range(n)]
	counter_topic = Counter([a for (a, b) in tuples])
	counter_diff = Counter([b for (a, b) in tuples])
	all_comb = n * (n - 2) * (n - 1) // 6
	ans = 0
	for (a, b) in tuples:
		same_topic = counter_topic[a] - 1
		same_diff = counter_diff[b] - 1
		ans += same_topic * same_diff
	return all_comb - ans
for i in range(int(input())):
	print(solve())


import os
import sys
from io import BytesIO, IOBase
from collections import Counter

def main():
	for _ in range(int(input())):
		n = int(input())
		s = []
		l = Counter()
		r = Counter()
		for _ in range(n):
			(a, b) = map(int, input().split())
			s.append((a, b))
			l[a] += 1
			r[b] += 1
		ans = n * (n - 1) * (n - 2) // 6
		left = set()
		for i in l:
			if l[i] > 1:
				left.add(i)
		right = set()
		for i in r:
			if r[i] > 1:
				right.add(i)
		for (i, j) in s:
			if i in left and j in right:
				ans -= (l[i] - 1) * (r[j] - 1)
		print(ans)
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')
main()


for _ in range(int(input())):
	n = int(input())
	ans = n * (n - 1) * (n - 2)
	ans //= 6
	a = []
	left = {}
	right = {}
	for i in range(n):
		(u, v) = map(int, input().split())
		a.append([u, v])
		if u in left:
			left[u] += 1
		else:
			left[u] = 1
		if v in right:
			right[v] += 1
		else:
			right[v] = 1
	for i in range(n):
		(u, v) = (a[i][0], a[i][1])
		x = left[u] - 1
		y = right[v] - 1
		ans -= x * y
	print(ans)


import sys
input = sys.stdin.readline

def solve():
	n = int(input())
	AB = [list(map(int, input().split())) for _ in range(n)]
	(cntT, cntD) = ({}, {})
	for i in range(n):
		(t, d) = AB[i]
		if t not in cntT:
			cntT[t] = 0
		if d not in cntD:
			cntD[d] = 0
		cntT[t] += 1
		cntD[d] += 1
	ans = n * (n - 1) * (n - 2) // 6
	for i in range(n):
		(t, d) = AB[i]
		ans -= (cntT[t] - 1) * (cntD[d] - 1)
	return ans
for _ in range(int(input())):
	print(solve())


import io, os, sys
input = io.BytesIO(os.read(0, os.fstat(0).st_size)).readline
output = sys.stdout.write

def solve(N, edges):
	(row_cnt, col_cnt) = ({}, {})
	for (r, c) in edges:
		row_cnt[r] = row_cnt.get(r, 0) + 1
		col_cnt[c] = col_cnt.get(c, 0) + 1
	res = N * (N - 1) * (N - 2) // 6
	for (r, c) in edges:
		res -= (row_cnt[r] - 1) * (col_cnt[c] - 1)
	return res

def main():
	T = int(input())
	for _ in range(T):
		N = int(input())
		edges = []
		for _ in range(N):
			(a, b) = list(map(int, input().split()))
			edges.append((a - 1, b - 1))
		out = solve(N, edges)
		output(str(out) + '\n')
main()


from collections import defaultdict
from sys import stdout
output = []
pairs = [(i, j) for i in range(4) for j in range(i + 1, 5)]
for _t in range(int(input())):
	n = int(input())
	same_topic = defaultdict(list)
	same_diff = defaultdict(int)
	for (t, d) in (map(int, input().split(' ')) for _ in range(n)):
		same_topic[t].append(d)
		same_diff[d] += 1
	invalid = 0
	for (topic, group) in same_topic.items():
		for diff in group:
			invalid += (len(group) - 1) * (same_diff[diff] - 1)
	output.append(n * (n - 1) // 2 * (n - 2) // 3 - invalid)
stdout.write('\n'.join(map(str, output)))


T = int(input())
for _ in range(T):
	n = int(input())
	difficult = dict()
	topic = dict()
	l = []
	for i in range(n):
		(a, b) = map(int, input().split())
		l.append((a, b))
		if b in difficult:
			difficult[b] += 1
		else:
			difficult[b] = 1
		if a in topic:
			topic[a] += 1
		else:
			topic[a] = 1
	ans = 0
	for i in l:
		ans += (topic[i[0]] - 1) * (difficult[i[1]] - 1)
	print(n * (n - 1) * (n - 2) // 6 - ans)


import sys, io, os
from os import path
if path.exists('input.txt'):
	sys.stdin = open('input.txt', 'r')
	sys.stdout = open('output.txt', 'w')
else:
	input = io.BytesIO(os.read(0, os.fstat(0).st_size)).readline
	pass

def main():
	n = int(input())
	a = []
	dist = [[] for i in range(n)]
	disk = [[] for i in range(n)]
	for i in range(n):
		b = list(map(int, input().split()))
		dist[b[0] - 1].append(b[1] - 1)
		disk[b[1] - 1].append(b[0] - 1)
		a.append([b[0] - 1, b[1] - 1])
	a.sort()
	dic1 = [0] * n
	dic2 = [0] * n
	for i in range(n):
		dic1[a[i][0]] += 1
		dic2[a[i][1]] += 1
	rep1 = []
	for i in range(n):
		if dic1[i] > 1:
			rep1.append(i)
	sum = 0
	for i in range(n):
		sum += (len(dist[a[i][0]]) - 1) * (len(disk[a[i][1]]) - 1)
	print(int(n * (n - 1) * (n - 2) / 6) - sum)
for _ in range(int(input())):
	main()


import collections
t = int(input())
while t:
	n = int(input())
	a = []
	b = []
	for i in range(n):
		(x, y) = map(int, input().split())
		a.append(x)
		b.append(y)
	answer = n * (n - 1) * (n - 2) // 6
	frequencyDicta = collections.Counter(a)
	frequencyDictb = collections.Counter(b)
	for i in range(n):
		answer = answer - (frequencyDicta[a[i]] - 1) * (frequencyDictb[b[i]] - 1)
	print(answer)
	t = t - 1


import sys
import io, os
input = io.BytesIO(os.read(0, os.fstat(0).st_size)).readline
import itertools
from collections import Counter, defaultdict
t = int(input())
for _ in range(t):
	n = int(input())
	A = [0] * n
	B = [0] * n
	AB = []
	ea = [set() for i in range(n)]
	eb = [set() for i in range(n)]
	for i in range(n):
		(a, b) = map(int, input().split())
		(a, b) = (a - 1, b - 1)
		A[i] = a
		B[i] = b
		AB.append((a, b))
		ea[a].add(b)
		eb[b].add(a)
	ans1 = 0
	da = [0] * n
	for a in A:
		da[a] += 1
	s1 = 0
	m1 = 0
	for (i, c) in enumerate(da):
		ans1 += m1 * c
		m1 = s1 * c + m1
		s1 += c
	ans2 = 0
	db = [0] * n
	for b in B:
		db[b] += 1
	s2 = 0
	m2 = 0
	for (i, c) in enumerate(db):
		ans2 += m2 * c
		m2 = s2 * c + m2
		s2 += c
	ans3 = n * (n - 1) * (n - 2) // 6
	for i in range(n):
		c = len(ea[i])
		if c >= 3:
			ans3 -= c * (c - 1) * (c - 2) // 6
	for i in range(n):
		c = len(eb[i])
		if c >= 3:
			ans3 -= c * (c - 1) * (c - 2) // 6
	for i in range(n):
		c = len(ea[i])
		if c < 2:
			continue
		temp = c * (c - 1) // 2 * (n + 2 - c)
		s = 0
		for x in ea[i]:
			s += db[x]
		temp -= (c - 1) * s
		ans3 -= temp
	for i in range(n):
		c = len(eb[i])
		if c < 2:
			continue
		temp = c * (c - 1) // 2 * (n + 2 - c)
		s = 0
		for x in eb[i]:
			s += da[x]
		temp -= (c - 1) * s
		ans3 -= temp
	for (a, b) in AB:
		temp = (da[a] - 1) * (db[b] - 1)
		ans3 -= temp
	ans = ans1 + ans2 - ans3
	print(ans)


import io
import os
input = io.BytesIO(os.read(0, os.fstat(0).st_size)).readline
from collections import defaultdict
for _ in range(int(input())):
	n = int(input())
	ans = n * (n - 1) * (n - 2) // 6
	pairs = set()
	l_frequencies = defaultdict(int)
	r_frequencies = defaultdict(int)
	for ___ in range(n):
		pair = tuple((int(num) for num in input().split()))
		pairs.add(pair)
		l_frequencies[pair[0]] += 1
		r_frequencies[pair[1]] += 1
	for pair in pairs:
		ans -= (l_frequencies[pair[0]] - 1) * (r_frequencies[pair[1]] - 1)
	print(ans)


for i in range(int(input())):
	n = int(input())
	zadachi = [[int(j) for j in input().split()] for k in range(n)]
	otv = 0
	a = dict()
	b = dict()
	for j in range(n):
		if zadachi[j][0] not in a:
			a[zadachi[j][0]] = 1
		else:
			a[zadachi[j][0]] += 1
		if zadachi[j][1] not in b:
			b[zadachi[j][1]] = 1
		else:
			b[zadachi[j][1]] += 1
	ans = n * (n - 1) * (n - 2) // 6
	for j in range(n):
		ans -= (a[zadachi[j][0]] - 1) * (b[zadachi[j][1]] - 1)
	print(ans)


import collections
import math
import itertools
import sys
import time
import random

def fast_input():
	return sys.stdin.readline().strip()
input = fast_input

def ints_input():
	return list((int(x) for x in input().split()))

def int_input():
	return int(input())

def solve():
	n = int_input()
	a = [None for _ in range(n)]
	b = [None for _ in range(n)]
	for i in range(n):
		(a[i], b[i]) = ints_input()
	a_counts = collections.Counter(a)
	b_counts = collections.Counter(b)
	a_two_families = 0
	a_three_families = 0
	b_two_families = 0
	b_three_families = 0
	two_overlaps = 0
	for i in range(n):
		a_count = a_counts[a[i]]
		b_count = b_counts[b[i]]
		a_two_families += (a_count - 1) * (n - a_count)
		b_two_families += (b_count - 1) * (n - b_count)
		a_three_families += (a_count - 1) * (a_count - 2) // 2
		b_three_families += (b_count - 1) * (b_count - 2) // 2
		two_overlaps += (a_count - 1) * (b_count - 1)
	good = n * (n - 1) * (n - 2) // 6 - two_overlaps
	print(good)
if True:
	for _ in range(int_input()):
		solve()
else:
	solve()


for _ in range(int(input())):
	n = int(input())
	t = dict()
	d = dict()
	arr = list()
	for i in range(n):
		(a, b) = map(int, input().split())
		arr.append([a, b])
		try:
			t[a] += 1
		except:
			t[a] = 1
		try:
			d[b] += 1
		except:
			d[b] = 1
	ans = n * (n - 1) * (n - 2) // 6
	for i in range(n):
		ans -= (t[arr[i][0]] - 1) * (d[arr[i][1]] - 1)
	print(ans)


import sys
input = lambda : sys.stdin.readline().rstrip('\r\n')
for _ in range(int(input())):
	n = int(input())
	ans = 0
	(c1, c2) = ([0] * (n + 1), [0] * (n + 1))
	pairs = []
	for i in range(n):
		(a, b) = map(int, input().split())
		c1[a] += 1
		c2[b] += 1
		pairs += [(a, b)]
	print(n * (n - 1) * (n - 2) // 6 - sum(((c1[a] - 1) * (c2[b] - 1) for (a, b) in pairs)))


import math
from collections import defaultdict
mod = 10 ** 9 + 7

def bexp(a, b):
	res = 1
	while b:
		if b % 2:
			res = res * a % mod
			b = b - 1
		else:
			a = a * a % mod
			b = b // 2
	return res
for cases in range(int(input())):
	n = int(input())
	l = []
	da = defaultdict(int)
	db = defaultdict(int)
	for i in range(0, n):
		(a, b) = map(int, input().split())
		l.append([a, b])
		da[a] += 1
		db[b] += 1
	ans = n * (n - 1) * (n - 2) // 6
	for i in range(0, n):
		a = l[i][0]
		b = l[i][1]
		ans = ans - (da[a] - 1) * (db[b] - 1)
	print(max(0, ans))


import os
import sys
from io import BytesIO, IOBase
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')
from collections import Counter
for _ in range(int(input())):
	n = int(input())
	diffcult = [0] * (n + 1)
	topic = [0] * (n + 1)
	g = [[] for i in range(n + 1)]
	for i in range(n):
		(u, v) = map(int, input().split())
		topic[u] += 1
		diffcult[v] += 1
		g[u].append(v)
	total = n * (n - 1) * (n - 2) // 6
	a = 0
	for i in range(1, n + 1):
		f = 0
		le = len(g[i])
		if le >= 2:
			if le >= 3:
				f = 1
			d = Counter(g[i])
			yy = 0
			for j in d:
				if d[j] >= 2 and diffcult[j] - d[j] >= 1:
					a += d[j] * (d[j] - 1) * (diffcult[j] - d[j])
				if diffcult[j] - d[j] > 0:
					yy += d[j] * (le - d[j]) * (diffcult[j] - d[j])
				if d[j] >= 2:
					a += d[j] * (d[j] - 1) * (n - diffcult[d[j]] - (le - d[j]))
				if f == 1:
					if d[j] >= 3:
						a += d[j] * (d[j] - 1) * (d[j] - 2)
					if d[j] >= 2:
						a += d[j] * (d[j] - 1) * (le - d[j])
			a += yy
	print(total - a)


import sys
IS_INTERACTIVE = False
input = input
if not IS_INTERACTIVE:
	(*data,) = sys.stdin.read().split('\n')[::-1]

	def input():
		return data.pop()

def fprint(*args, **kwargs):
	print(*args, **kwargs, flush=True)

def eprint(*args, **kwargs):
	print(*args, **kwargs, file=sys.stderr)

def naive(topics, diffs):
	n = len(topics)
	cnt = 0
	for i in range(n):
		for j in range(i + 1, n):
			for k in range(j + 1, n):
				if len({topics[i], topics[j], topics[k]}) == 3 or len({diffs[i], diffs[j], diffs[k]}) == 3:
					cnt += 1
	return cnt

def fast(topics, diffs):
	tcnt = [0] * (n + 1)
	dcnt = [0] * (n + 1)
	for (t, d) in zip(topics, diffs):
		tcnt[t] += 1
		dcnt[d] += 1
	pairs = list(zip(topics, diffs))
	ans = n * (n - 1) * (n - 2) // 6
	for i in range(n):
		c0 = tcnt[topics[i]]
		c1 = dcnt[diffs[i]]
		c0 -= 1
		c1 -= 1
		if c0 and c1:
			ans -= c0 * c1
	return ans
for _ in range(int(input())):
	n = int(input())
	topics = []
	diffs = []
	for _ in range(n):
		(t, d) = map(int, input().split())
		topics.append(t)
		diffs.append(d)
	print(fast(topics, diffs))


t = int(input())
mass = list()
dic1 = dict()
dic2 = dict()
for num in range(t):
	n = int(input())
	mass.clear()
	dic1.clear()
	dic2.clear()
	for i in range(n):
		(a, b) = map(int, input().split())
		if a in dic1.keys():
			dic1[a] += 1
		else:
			dic1[a] = 0
		if b in dic2.keys():
			dic2[b] += 1
		else:
			dic2[b] = 0
		mass.append([a, b])
	ans = n * (n - 1) * (n - 2) // 6
	for i in range(n):
		ans -= dic1[mass[i][0]] * dic2[mass[i][1]]
	print(ans)


import os
import sys
from collections import Counter, defaultdict, deque
from io import BytesIO, IOBase
from math import gcd, inf, sqrt, ceil

def lcm(a, b):
	return a * b // gcd(a, b)

def sieve():
	global spf, adj, MAXN
	spf[1] = 1
	for i in range(2, MAXN):
		spf[i] = i
	for i in range(2, MAXN):
		if i * i > MAXN:
			break
		if spf[i] == i:
			for j in range(i * i, MAXN, i):
				if spf[j] == j:
					spf[j] = i

def getdistinctFactorization(n):
	global adj, spf, MAXN
	for i in range(1, n + 1):
		index = 1
		x = i
		if x != 1:
			adj[i].append(spf[x])
		x = x // spf[x]
		while x != 1:
			if adj[i][index - 1] != spf[x]:
				adj[i].append(spf[x])
				index += 1
			x = x // spf[x]

def printDivisors(n):
	i = 2
	z = [1, n]
	while i <= sqrt(n):
		if n % i == 0:
			if n / i == i:
				z.append(i)
			else:
				z.append(i)
				z.append(n // i)
		i = i + 1
	return z

def create(n, x, f):
	pq = len(bin(n)[2:])
	if f == 0:
		tt = min
	else:
		tt = max
	dp = [[inf] * n for _ in range(pq)]
	dp[0] = x
	for i in range(1, pq):
		for j in range(n - (1 << i) + 1):
			dp[i][j] = tt(dp[i - 1][j], dp[i - 1][j + (1 << i - 1)])
	return dp

def enquiry(l, r, dp, f):
	if l > r:
		return inf if not f else -inf
	if f == 1:
		tt = max
	else:
		tt = min
	pq1 = len(bin(r - l + 1)[2:]) - 1
	return tt(dp[pq1][l], dp[pq1][r - (1 << pq1) + 1])

def SieveOfEratosthenes(n):
	prime = [True for i in range(n + 1)]
	p = 2
	while p * p <= n:
		if prime[p] == True:
			for i in range(p * p, n + 1, p):
				prime[i] = False
		p += 1
	x = []
	for i in range(2, n + 1):
		if prime[i]:
			x.append(i)
	return x

def main():
	for _ in range(int(input())):
		n = int(input())
		x = defaultdict(list)
		y = Counter()
		for i in range(n):
			(a, b) = map(int, input().split())
			x[a].append(b)
			y[b] += 1
		an = 0
		for i in x:
			xx = 0
			for j in x[i]:
				xx += y[j] - 1
			an += (len(x[i]) - 1) * xx
		print(n * (n - 1) * (n - 2) // 6 - an)
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')
main()


import os, sys
from io import BytesIO, IOBase

def main():
	for _ in range(int(input())):
		n = int(input())
		(topic, diff) = ([[] for _ in range(n + 1)], [0] * (n + 1))
		for _ in range(n):
			(u1, v1) = map(int, input().split())
			topic[u1].append(v1)
			diff[v1] += 1
		ans = n * (n - 1) * (n - 2) // 6
		for i in range(1, n + 1):
			for j in topic[i]:
				ans -= (len(topic[i]) - 1) * (diff[j] - 1)
		print(ans)
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')
main()


for _ in range(int(input())):
	n = int(input())
	l = []
	for i in range(n):
		l.append(list(input().split()))
	t = n * (n - 1) * (n - 2) // 6
	xd = {}
	yd = {}
	for i in l:
		(x, y) = i
		if x in xd:
			xd[x] += 1
		else:
			xd[x] = 1
		if y in yd:
			yd[y] += 1
		else:
			yd[y] = 1
	s = 0
	for i in l:
		(x, y) = i
		s += (xd[x] - 1) * (yd[y] - 1)
	print(t - s)


for _ in range(int(input())):
	n = int(input())
	a = list()
	b = list()
	d1 = [-1] * (n + 1)
	d2 = [-1] * (n + 1)
	for i in range(n):
		(x, y) = map(int, input().split())
		a.append(x)
		b.append(y)
		d1[x] += 1
		d2[y] += 1
	vid = n * (n - 1) * (n - 2) // 6
	for i in range(n):
		vid -= d1[a[i]] * d2[b[i]]
	print(vid)


from sys import *
for _ in range(int(stdin.readline())):
	n = int(stdin.readline())
	ans = n * (n - 1) * (n - 2)
	ans //= 6
	a = []
	left = {}
	right = {}
	for i in range(n):
		(u, v) = map(int, stdin.readline().split())
		a.append([u, v])
		if u in left:
			left[u] += 1
		else:
			left[u] = 1
		if v in right:
			right[v] += 1
		else:
			right[v] = 1
	for i in range(n):
		(u, v) = (a[i][0], a[i][1])
		x = left[u] - 1
		y = right[v] - 1
		ans -= x * y
	stdout.write(str(ans) + '\n')


def I():
	return input().strip()

def II():
	return int(input().strip())

def LI():
	return [*map(int, input().strip().split())]
import sys, os, copy, string, math, time, functools, fractions
from io import BytesIO, IOBase
from heapq import heappush, heappop, heapify
from bisect import bisect_left, bisect_right
from collections import deque, defaultdict, Counter, OrderedDict
from itertools import permutations, chain, combinations, groupby
from operator import itemgetter
from types import GeneratorType
from typing import Iterable, TypeVar, Union
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')

def bootstrap(f, stack=[]):

	def wrappedfunc(*args, **kwargs):
		if stack:
			return f(*args, **kwargs)
		else:
			to = f(*args, **kwargs)
			while True:
				if type(to) is GeneratorType:
					stack.append(to)
					to = next(to)
				else:
					stack.pop()
					if not stack:
						break
					to = stack[-1].send(to)
			return to
	return wrappedfunc

def nc3(x):
	return x * (x - 1) * (x - 2) // 6

def sumPairs(arr, n):
	sm = 0
	for i in range(n):
		sm = sm + arr[i] * (2 * n)
	sm -= sum(arr) * 2
	return sm // 2

def main():
	n = II()
	(a, b) = ([], [])
	for i in range(n):
		(x, y) = LI()
		a.append(x - 1)
		b.append(y - 1)
	tot = nc3(n)
	fb = [0] * n
	for i in b:
		fb[i] += 1
	mp = defaultdict(list)
	for i in range(n):
		mp[a[i]].append(fb[b[i]] - 1)
	sub = 0
	for (key, elem) in mp.items():
		sub += sumPairs(elem, len(elem))
	print(tot - sub)
for _ in range(II()):
	main()


from collections import Counter
import sys
readline = sys.stdin.readline
T = int(readline())
for t in range(T):
	N = int(readline())
	(A, B) = ([], [])
	for _ in range(N):
		(a, b) = map(int, readline().split())
		A.append(a)
		B.append(b)
	C_A = Counter(A)
	C_B = Counter(B)
	ans = N * (N - 1) * (N - 2)
	S = 0
	for c in C_A.values():
		S += c * (c - 1)
	for c in C_B.values():
		S += c * (c - 1)
	ans -= S * 3 * (N - 2)
	for i in range(N):
		ans += (C_A[A[i]] - 1) * (C_B[B[i]] - 1) * 6
	for c in C_A.values():
		ans += c * (c - 1) * (c - 2) * 3
	for c in C_B.values():
		ans += c * (c - 1) * (c - 2) * 3
	for c in C_A.values():
		ans -= c * (c - 1) * (c - 2)
	for c in C_B.values():
		ans -= c * (c - 1) * (c - 2)
	ansA = N * (N - 1) * (N - 2)
	for c in C_A.values():
		ansA -= c * (c - 1) * (N - 2) * 3
	for c in C_A.values():
		ansA += c * (c - 1) * (c - 2) * 3
	for c in C_A.values():
		ansA -= c * (c - 1) * (c - 2)
	ansB = N * (N - 1) * (N - 2)
	for c in C_B.values():
		ansB -= c * (c - 1) * (N - 2) * 3
	for c in C_B.values():
		ansB += c * (c - 1) * (c - 2) * 3
	for c in C_B.values():
		ansB -= c * (c - 1) * (c - 2)
	ans = ansA + ansB - ans
	ans //= 6
	print(ans)


from collections import Counter

def cn3(m):
	return m * (m - 1) * (m - 2) // 6

def solve_case():
	n = int(input())
	a = [-1] * n
	b = [-1] * n
	for i in range(n):
		(a[i], b[i]) = map(int, input().split())
	ca = Counter(a)
	cb = Counter(b)
	pair_sum = 0
	for i in range(n):
		pair_sum += (ca[a[i]] - 1) * (cb[b[i]] - 1)
	ans = cn3(n) - pair_sum
	print(ans)
T = int(input())
for t in range(T):
	solve_case()


import sys
from sys import stdin
tt = int(stdin.readline())
ANS = []
for loop in range(tt):
	n = int(stdin.readline())
	ab = []
	anum = {}
	bnum = {}
	for i in range(n):
		(a, b) = map(int, stdin.readline().split())
		ab.append((a, b))
		if a not in anum:
			anum[a] = 0
		if b not in bnum:
			bnum[b] = 0
		anum[a] += 1
		bnum[b] += 1
	twonl = 0
	for a in anum:
		c = anum[a]
		twonl += c * (c - 1) // 2 * (n - c)
	for b in bnum:
		c = bnum[b]
		twonl += c * (c - 1) // 2 * (n - c)
	tans = 0
	for (a, b) in ab:
		tans += (anum[a] - 1) * (bnum[b] - 1)
	aans = 0
	for a in anum:
		c = anum[a]
		aans += c * (c - 1) * (c - 2) // 6
	for b in bnum:
		c = bnum[b]
		aans += c * (c - 1) * (c - 2) // 6
	aans = n * (n - 1) * (n - 2) // 6 - (twonl - tans + aans)
	dpA = [0, 0, 0]
	for a in anum:
		c = anum[a]
		dpA[2] += dpA[1] * c
		dpA[1] += dpA[0] * c
		dpA[0] += c
	dpB = [0, 0, 0]
	for b in bnum:
		c = bnum[b]
		dpB[2] += dpB[1] * c
		dpB[1] += dpB[0] * c
		dpB[0] += c
	twoans = dpA[-1] + dpB[-1]
	ANS.append(str(twoans - aans))
print('\n'.join(ANS))


import sys
input = sys.stdin.readline
from collections import Counter as C
f = input
for i in ' ' * int(f()):
	n = int(f())
	ls = []
	l1 = C()
	l2 = C()
	for i in ' ' * n:
		(a, b) = map(int, f().split())
		ls.append([a, b])
		l1[a] += 1
		l2[b] += 1
	z = n * (n - 1) * (n - 2) // 6
	for (a, b) in ls:
		z -= (l1[a] - 1) * (l2[b] - 1)
	print(z)


from collections import Counter
for i in range(int(input())):
	n = int(input())
	ls = []
	l1 = Counter()
	l2 = Counter()
	for i in range(n):
		(a, b) = map(int, input().split())
		ls.append([a, b])
		l1[a] += 1
		l2[b] += 1
	z = n * (n - 1) * (n - 2) // 6
	for (a, b) in ls:
		z -= (l1[a] - 1) * (l2[b] - 1)
	print(z)


from collections import defaultdict, Counter, deque
from math import sqrt, log10, log, floor, factorial, gcd
from bisect import bisect_left, bisect_right
from itertools import permutations, combinations
import sys, io, os
input = sys.stdin.readline
inf = float('inf')
mod = 10 ** 9 + 7

def yn(a):
	print('YES' if a else 'NO')
ceil = lambda a, b: (a + b - 1) // b
t = int(input())
for i in range(t):
	n = int(input())
	topic = defaultdict(int)
	diff = defaultdict(int)
	m = []
	for i in range(n):
		l = [int(i) for i in input().split()]
		m.append(l)
		topic[l[0]] += 1
		diff[l[1]] += 1
	nc3 = lambda n: n * (n - 1) * (n - 2) // 6
	counter = nc3(n)
	for i in range(n):
		a = topic[m[i][0]]
		b = diff[m[i][1]]
		counter -= (a - 1) * (b - 1)
	print(counter)


from collections import Counter
for _ in range(int(input())):
	n = int(input())
	a = []
	b = []
	c = dict()
	d = dict()
	for _ in range(n):
		(a1, b1) = map(int, input().split())
		a.append(a1)
		b.append(b1)
		c[a1] = c.get(a1, 0) + 1
		d[b1] = d.get(b1, 0) + 1
	r = n * (n - 1) * (n - 2) / 6
	for i in range(n):
		r -= (c[a[i]] - 1) * (d[b[i]] - 1)
	print(int(r))


import sys
input = sys.stdin.readline
from collections import Counter
for t in range(int(input())):
	N = int(input())
	L = [tuple(map(int, input().split())) for i in range(N)]
	C1 = Counter()
	C2 = Counter()
	for (i, j) in L:
		C1[i] += 1
		C2[j] += 1
	T = N * (N - 1) * (N - 2) // 6
	for (i, j) in L:
		T -= (C1[i] - 1) * (C2[j] - 1)
	print(T)


from collections import defaultdict
for _ in range(int(input())):
	n = int(input())
	li = []
	topics = defaultdict(list)
	diff = defaultdict(int)
	for i in range(n):
		(a, b) = map(int, input().split())
		topics[a].append(b)
		diff[b] += 1
	to_sub = 0
	for (k, v) in topics.items():
		p = len(v)
		for i in range(p):
			to_sub += (diff[v[i]] - 1) * (p - 1)
	total_comb = n * (n - 1) * (n - 2) // 6
	print(total_comb - to_sub)


mxn = 10 ** 10
for _ in range(int(input())):
	n = int(input())
	dct = [[] for i in range(n + 1)]
	second = [0] * (n + 1)
	for i in range(n):
		(a, b) = map(int, input().split())
		dct[a].append(b)
		second[b] += 1
	temp = 0
	for ls in dct:
		ln = len(ls) - 1
		for num in ls:
			temp += ln * (second[num] - 1)
	res = n * (n - 1) * (n - 2) // 6 - temp
	print(res)


import collections
T = input()
T = int(T)
for i in range(T):
	n = input()
	n = int(n)
	topics = [0 for _ in range(n)]
	diffs = [0 for _ in range(n)]
	ans = 0
	topic_dict = [0 for _ in range(n)]
	diff_dict = [0 for _ in range(n)]
	for j in range(n):
		(a, b) = map(int, input().split())
		topics[j] = a - 1
		diffs[j] = b - 1
		topic_dict[a - 1] += 1
		diff_dict[b - 1] += 1
	for (t, d) in zip(topics, diffs):
		ans += (topic_dict[t] - 1) * (diff_dict[d] - 1)
	print(n * (n - 1) * (n - 2) // 6 - ans)


import math
import heapq
import string
from collections import deque
from bisect import bisect, bisect_left, bisect_right, insort
import sys
input = sys.stdin.readline
S = lambda : input().rstrip()
I = lambda : int(S())
M = lambda : map(int, S().split())
L = lambda : list(M())
H = 1000000000 + 7
for _ in range(I()):
	n = I()
	l = []
	for i in range(n):
		l.append(L())
	d1 = {}
	d2 = {}
	for i in range(n):
		d1[l[i][0]] = d1.get(l[i][0], 0) + 1
		d2[l[i][1]] = d2.get(l[i][1], 0) + 1
	p = 0
	for i in range(n):
		p += (d1[l[i][0]] - 1) * (d2[l[i][1]] - 1)
	print(n * (n - 1) * (n - 2) // 6 - p)


for _ in range(int(input())):
	n = int(input())
	cnt1 = [0] * n
	cnt2 = [0] * n
	li = []
	for _ in range(n):
		line = input().split()
		a = int(line[0]) - 1
		b = int(line[1]) - 1
		cnt1[a] += 1
		cnt2[b] += 1
		li.append((a, b))
	total = 1
	for i in range(3):
		total *= n - i
	for i in range(1, 4):
		total //= i
	for (a, b) in li:
		total -= (cnt1[a] - 1) * (cnt2[b] - 1)
	print(total)


import os
import sys
from io import BytesIO, IOBase
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')
from collections import defaultdict, deque
from math import ceil, floor, sqrt, log2, gcd, pi
from heapq import heappush, heappop
from bisect import bisect_left, bisect
from functools import reduce
from copy import deepcopy
import sys
abc = 'abcdefghijklmnopqrstuvwxyz'
ABC = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
for _ in range(int(input())):
	n = int(input())
	arr = []
	diff = defaultdict(int)
	num = defaultdict(int)
	check = defaultdict(int)
	for _ in range(n):
		(a, b) = map(int, input().split())
		num[a] += 1
		diff[b] += 1
		check[tuple([a, b])] += 1
	ans = 0
	for (a, b) in check:
		ans += (num[a] - 1) * (diff[b] - 1)
	tot = n * (n - 1) * (n - 2) // 6
	print(tot - ans)


from __future__ import division, print_function
import math
import sys
import os
from io import BytesIO, IOBase
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')

def print(*args, **kwargs):
	(sep, file) = (kwargs.pop('sep', ' '), kwargs.pop('file', sys.stdout))
	at_start = True
	for x in args:
		if not at_start:
			file.write(sep)
		file.write(str(x))
		at_start = False
	file.write(kwargs.pop('end', '\n'))
	if kwargs.pop('flush', False):
		file.flush()
if sys.version_info[0] < 3:
	(sys.stdin, sys.stdout) = (FastIO(sys.stdin), FastIO(sys.stdout))
else:
	(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')

def I():
	return int(input())

def lint():
	return list(map(int, input().split()))

def insr():
	s = input().strip()
	return list(s[:len(s)])

def invr():
	return map(int, input().split())
import itertools
from sys import maxsize, stdout, stdin, stderr
mod = int(1000000000.0 + 7)
import sys

def S():
	return list(map(str, input().strip()))

def grid(r, c):
	return [lint() for i in range(r)]
from collections import defaultdict, Counter, deque
import math
import heapq
from heapq import heappop, heappush
import bisect
from math import factorial, inf
from itertools import groupby
from itertools import permutations as comb

def gcd(a, b):
	while b:
		a %= b
		tmp = a
		a = b
		b = tmp
	return a

def lcm(a, b):
	return a // gcd(a, b) * b

def check_prime(n):
	for i in range(2, int(n ** (1 / 2)) + 1):
		if not n % i:
			return False
	return True

def nCr(n, r):
	return fact(n) // (fact(r) * fact(n - r))

def fact(n):
	res = 1
	for i in range(2, n + 1):
		res = res * i
	return res

def primefactors(n):
	num = 0
	while n % 2 == 0:
		num += 1
		n = n / 2
	for i in range(3, int(math.sqrt(n)) + 1, 2):
		while n % i == 0:
			num += 1
			n = n // i
	if n > 2:
		num += 1
	return num

def ask(a, b, c):
	print(c, a, b, flush=True)
	n = I()
	return n

def linear_sieve(n):
	is_composite = [False] * n
	prime = []
	for i in range(2, n):
		if not is_composite[i]:
			prime.append(i)
		for j in prime:
			is_composite[i * j] = True
			if i % prime == 0:
				break
	return prime

def dfs(i, p, d):
	(a, tmp) = (0, 0)
	for j in d[i]:
		if j != p:
			a += 1
			tmp += dfs(j, i)
	if a == 0:
		return 0
	return tmp / a + 1

def primeFactors(n):
	l = []
	while n % 2 == 0:
		l.append(2)
		n = n // 2
	for i in range(3, int(math.sqrt(n)) + 1, 2):
		while n % i == 0:
			l.append(i)
			n = n // i
	if n > 2:
		l.append(n)
	return l
d = []
primes = []
prim = [0] * (10 ** 5 + 1)

def sieve(n):
	for i in range(n):
		d.append(i)
	for i in range(2, n):
		if d[i] == i:
			prim[i] = 1
			primes.append(i)
		j = 0
		while j < len(primes) and primes[j] <= d[i] and (primes[j] * i < n):
			d[i * primes[j]] = primes[j]
			j += 1

def primeFactors(n):
	factors = []
	while n != 1:
		factors.append(d[n])
		n //= d[n]
	return factors
mod = 1000000007
t = 1
t = I()
for _ in range(t):
	n = I()
	s = []
	d = defaultdict(lambda : 0)
	d1 = defaultdict(lambda : 0)
	for i in range(n):
		(a, b) = lint()
		d[a] += 1
		d1[b] += 1
		s.append([a, b])
	ans = n * (n - 1) * (n - 2) // 6
	for i in range(n):
		(a, b) = s[i]
		ans -= (d[a] - 1) * (d1[b] - 1)
	print(ans)


try:
	import sys
	from functools import lru_cache, cmp_to_key
	from heapq import merge, heapify, heappop, heappush
	from collections import defaultdict as dd, deque, Counter as C
	from itertools import combinations as comb, permutations as perm
	from bisect import bisect_left as bl, bisect_right as br, bisect, insort
	from time import perf_counter
	from fractions import Fraction
	import copy
	from copy import deepcopy
	import time
	starttime = time.time()
	mod = int(pow(10, 9) + 7)
	mod2 = 998244353

	def data():
		return sys.stdin.readline().strip()

	def out(*var, end='\n'):
		sys.stdout.write(' '.join(map(str, var)) + end)

	def L():
		return list(sp())

	def sl():
		return list(ssp())

	def sp():
		return map(int, data().split())

	def ssp():
		return map(str, data().split())

	def l1d(n, val=0):
		return [val for i in range(n)]

	def l2d(n, m, val=0):
		return [l1d(n, val) for j in range(m)]

	def A2(n, m):
		return [[0] * m for i in range(n)]

	def A(n):
		return [0] * n
	sys.stdin = open('input.txt', 'r')
	sys.stdout = open('output.txt', 'w')
except:
	pass
import sys
input = sys.stdin.readline
for _ in range(L()[0]):
	n = L()[0]
	X = [L() for i in range(n)]
	par = [i for i in range(n + 1)]
	Y = [[X[i][0], i + 1] for i in range(n)]
	Y.sort()
	d = dd(int)
	for i in range(n):
		(x, y) = Y[i]
		if x not in d:
			d[x] = par[y]
		else:
			par[y] = d[x]
	par1 = par[:]
	par = [i for i in range(n + 1)]
	Y = [[X[i][1], i + 1] for i in range(n)]
	Y.sort()
	d = dd(int)
	for i in range(n):
		(x, y) = Y[i]
		if x not in d:
			d[x] = par[y]
		else:
			par[y] = d[x]
	ans = n * (n - 1) * (n - 2) // 6
	d1 = dd(int)
	d2 = dd(int)
	for i in range(1, n + 1):
		d1[par[i]] += 1
		d2[par1[i]] += 1
	for i in range(1, n + 1):
		x = d1[par[i]]
		y = d2[par1[i]]
		ans -= (x - 1) * (y - 1)
	print(ans)


import sys
input = sys.stdin.buffer.readline

def process(A):
	n = len(A)
	total = n * (n - 1) * (n - 2) // 6
	pairs = {}
	topic = {}
	diff = {}
	for i in range(n):
		(a, b) = A[i]
		if (a, b) not in pairs:
			pairs[a, b] = 0
		pairs[a, b] += 1
		if a not in topic:
			topic[a] = 0
		topic[a] += 1
		if b not in diff:
			diff[b] = 0
		diff[b] += 1
	bad = 0
	for x in pairs:
		(a, b) = x
		y = pairs[x]
		z1 = topic[a]
		z2 = diff[b]
		bad_triple1 = y * (y - 1) * (y - 2) // 6
		bad += bad_triple1
		bad_triple2 = y * (y - 1) // 2 * (z1 - 2) - y * (y - 1) * (y - 2) // 6
		bad += bad_triple2
		bad_triple3 = y * (y - 1) // 2 * (z2 - 2) - y * (y - 1) * (y - 2) // 6
		bad += bad_triple3
		unmatched_pairs = n - z1 - z2 + y
		bad_triple4 = y * (y - 1) // 2 * unmatched_pairs
		bad += bad_triple4
		other_a = z1 - y
		other_b = z2 - y
		bad_triple5 = y * other_a * other_b
		bad += bad_triple5
	return total - bad
t = int(input())
for i in range(t):
	n = int(input())
	A = []
	for j in range(n):
		(a, b) = [int(x) for x in input().split()]
		A.append([a, b])
	answer = process(A)
	sys.stdout.write(str(answer) + '\n')


import sys
import io
import math
import collections
import decimal
import itertools
import bisect
import heapq

def input():
	return sys.stdin.readline()[:-1]
INF = 10 ** 10

def solve(N, T):
	counter1 = collections.Counter([a for (a, b) in T])
	counter2 = collections.Counter([b for (a, b) in T])
	v1 = 0
	for (a, n) in counter1.items():
		if n >= 2:
			v1 += n * (n - 1) // 2 * (N - n)
	v2 = 0
	for (a, n) in counter1.items():
		if n >= 3:
			v2 += n * (n - 1) * (n - 2) // 6
	v3 = 0
	for (a, b) in T:
		v3 += (counter1[a] - 1) * (counter2[b] - 1)
	v4 = 0
	for (a, n) in counter2.items():
		if n >= 2:
			v4 += n * (n - 1) // 2 * (N - n)
	v5 = 0
	for (a, n) in counter2.items():
		if n >= 3:
			v5 += n * (n - 1) * (n - 2) // 6
	m = N * (N - 1) * (N - 2) // 6
	ans = m - v1 - v2 + (m - v4 - v5) - (m - v1 - v2 + v3 - v4 - v5)
	return ans
T0 = int(input())
for _ in range(T0):
	N = int(input())
	T = []
	for _ in range(N):
		(a, b) = map(int, input().split())
		T.append((a, b))
	print(solve(N, T))


import math
from collections import defaultdict, Counter
from bisect import bisect_left
from sys import stdin
input = stdin.readline
t = int(input())
for _ in range(t):
	n = int(input())
	a = []
	b = defaultdict(int)
	c = defaultdict(int)
	for i in range(n):
		a.append(tuple(map(int, input().split())))
		b[a[-1][0]] += 1
		c[a[-1][1]] += 1
	ans = n * (n - 1) * (n - 2) // 6
	for i in range(n):
		ans -= (b[a[i][0]] - 1) * (c[a[i][1]] - 1)
	print(ans)


from collections import defaultdict
t = int(input())
for _ in range(t):
	n = int(input())
	l = defaultdict(int)
	r = defaultdict(int)
	ll = defaultdict(list)
	lr = defaultdict(list)
	for i in range(n):
		(x, y) = map(int, input().split())
		l[x] += 1
		r[y] += 1
		ll[x].append(y)
		lr[y].append(x)
	sl = defaultdict(int)
	for x in ll:
		for y in ll[x]:
			sl[x] += r[y]
	invalid = 0
	for x in l:
		invalid += (l[x] - 1) * (sl[x] - l[x])
	print(n * (n - 1) * (n - 2) // 6 - invalid)


import sys
input = lambda : sys.stdin.readline().rstrip()
import bisect
import itertools
from collections import deque
from collections import Counter

def solve():
	n = int(input())
	ab = [list(map(int, input().split())) for _ in range(n)]
	a = Counter()
	b = Counter()
	for i in range(n):
		a[ab[i][0]] += 1
		b[ab[i][1]] += 1
	ans = n * (n - 1) * (n - 2) // 6
	for i in range(n):
		ans -= (a[ab[i][0]] - 1) * (b[ab[i][1]] - 1)
	print(ans)
t = int(input())
for _ in range(t):
	solve()


t = int(input())
out = ''
for _ in range(t):
	n = int(input())
	a = []
	b = []
	countA = [[] for _ in range(n)]
	countB = [[] for _ in range(n)]
	for _ in range(n):
		(ai, bi) = [int(x) - 1 for x in input().split()]
		a.append(ai)
		b.append(bi)
		countA[ai].append(bi)
		countB[bi].append(ai)
	ways = n * (n - 1) * (n - 2) // (3 * 2)
	for rep in countA:
		for x in rep:
			ways -= (len(countB[x]) - 1) * (len(rep) - 1)
	out += str(ways) + '\n'
print(out)


import sys
input = sys.stdin.readline

def iinput():
	return int(input())

def sinput():
	return input().rstrip()

def i0input():
	return int(input()) - 1

def linput():
	return list(input().split())

def liinput():
	return list(map(int, input().split()))

def miinput():
	return map(int, input().split())

def li0input():
	return list(map(lambda x: int(x) - 1, input().split()))

def mi0input():
	return map(lambda x: int(x) - 1, input().split())
INF = 10 ** 20
MOD = 1000000007
t = iinput()
from collections import defaultdict
for _ in [0] * t:
	n = iinput()
	A = defaultdict(int)
	B = defaultdict(int)
	all = []
	for _ in [0] * n:
		(a, b) = li0input()
		A[a] += 1
		B[b] += 1
		all.append((a, b))
	ans1 = n * (n - 1) * (n - 2) // 6
	ans2 = n * (n - 1) * (n - 2) // 6
	for v in A.values():
		if v >= 2:
			ans1 -= (n - v) * v * (v - 1) // 2
		if v >= 3:
			ans1 -= v * (v - 1) * (v - 2) // 6
	for v in B.values():
		if v >= 2:
			ans2 -= (n - v) * v * (v - 1) // 2
		if v >= 3:
			ans2 -= v * (v - 1) * (v - 2) // 6
	bar_joint = 0
	for (a, b) in all:
		bar_joint += max(0, A[a] - 1) * max(0, B[b] - 1)
	joint = ans1 + ans2 + bar_joint - n * (n - 1) * (n - 2) // 6
	print(ans1 + ans2 - joint)


from sys import stdin, stdout
from math import gcd, sqrt, factorial, pi, inf
from collections import deque, defaultdict
from bisect import bisect, bisect_left
from time import time
from itertools import permutations as per
from heapq import heapify, heappush, heappop, heappushpop
input = stdin.readline
R = lambda : map(int, input().split())
I = lambda : int(input())
S = lambda : input().rstrip('\r\n')
L = lambda : list(R())
P = lambda x: stdout.write(str(x) + '\n')
lcm = lambda x, y: x * y // gcd(x, y)
nCr = lambda x, y: f[x] * inv(f[y] * f[x - y] % N) % N
inv = lambda x: pow(x, N - 2, N)
sm = lambda x: (x ** 2 + x) // 2
N = 10 ** 9 + 7
for _ in range(I()):
	n = I()
	a = [0] * (n + 1)
	b = [0] * (n + 1)
	d = []
	for i in range(n):
		(x, y) = R()
		a[x] += 1
		b[y] += 1
		d += ((x, y),)
	ans = n * (n - 1) * (n - 2) // 6
	for i in range(n):
		ans -= (a[d[i][0]] - 1) * (b[d[i][1]] - 1)
	print(ans)


from collections import defaultdict
from sys import stdin, stdout
for _ in range(int(stdin.readline())):
	n = int(stdin.readline())
	(da, db) = (defaultdict(int), defaultdict(int))
	arr = []
	for _ in range(n):
		(a, b) = map(int, stdin.readline().split())
		da[a] += 1
		db[b] += 1
		arr.append([a, b])
	ans = 0
	for (a, b) in arr:
		ans += (da[a] - 1) * (db[b] - 1)
	stdout.write(str(n * (n - 1) * (n - 2) // 6 - ans) + '\n')


t = int(input())
for t1 in range(t):
	n = int(input())
	a = [0] * n
	b = [0] * n
	a1 = {}
	b1 = {}
	u1 = []
	u2 = []
	for i in range(n):
		(fi, se) = map(int, input().split())
		a[i] = fi
		b[i] = se
		if a[i] in a1:
			a1[a[i]] += 1
		else:
			a1[a[i]] = 1
			u1.append(a[i])
		if b[i] in b1:
			b1[b[i]] += 1
		else:
			b1[b[i]] = 1
			u2.append(b[i])
	sum = int(n * (n - 1) * (n - 2) / 6)
	for i in range(n):
		sum = sum - (a1[a[i]] - 1) * (b1[b[i]] - 1)
	print(sum)


from sys import stdin, stdout
for _ in range(int(stdin.readline())):
	n = int(stdin.readline())
	fr1 = [0] * (n + 1)
	fr2 = [0] * (n + 1)
	l = []
	for i in range(n):
		(x, y) = list(map(int, stdin.readline().split()))
		fr1[x - 1] += 1
		fr2[y - 1] += 1
		l.append([x - 1, y - 1])
	ans = n * (n - 1) * (n - 2) // 6
	x = 0
	for i in range(n):
		x += (fr1[l[i][0]] - 1) * (fr2[l[i][1]] - 1)
	stdout.write(str(ans - x) + '\n')


z = int(input())
for i in range(z):
	n = int(input())
	table1 = [-1] * (n + 1)
	table2 = [-1] * (n + 1)
	a = []
	for i in range(n):
		a.append(list(map(int, input().split())))
		table1[a[i][0]] += 1
		table2[a[i][1]] += 1
	total = n * (n - 1) * (n - 2) // 6
	for i in range(n):
		total -= table1[a[i][0]] * table2[a[i][1]]
	print(total)


for t in range(int(input())):
	n = int(input())
	dx = {}
	dy = {}
	arr = []
	for i in range(n):
		(x, y) = [int(k) for k in input().split()]
		dx[x] = dx.get(x, 0) + 1
		dy[y] = dy.get(y, 0) + 1
		arr.append((x, y))
	ans = n * (n - 1) // 2 * (n - 2) // 3
	for (x, y) in arr:
		ans -= (dx[x] - 1) * (dy[y] - 1)
	print(ans)


def solve():
	n = int(input())
	tot = n * (n - 1) * (n - 2) // 6
	(ca, cb) = ([0] * (n + 1), [0] * (n + 1))
	(a, b) = ([0] * n, [0] * n)
	for i in range(n):
		(a[i], b[i]) = map(int, input().split())
		ca[a[i]] = ca[a[i]] + 1
		cb[b[i]] = cb[b[i]] + 1
	for i in range(n):
		tot = tot - (ca[a[i]] - 1) * (cb[b[i]] - 1)
	print(tot)
t = int(input())
for i in range(t):
	solve()


T = int(input())
from collections import Counter
for _ in range(T):
	N = int(input())
	AB = [tuple(map(int, input().split())) for i in range(N)]
	ans = N * (N - 1) * (N - 2) // 6
	ca = Counter()
	cb = Counter()
	for (a, b) in AB:
		ca[a] += 1
		cb[b] += 1
	for (a, b) in AB:
		ans -= (ca[a] - 1) * (cb[b] - 1)
	print(ans)


for _ in range(int(input())):
	n = int(input())
	d1 = {}
	d2 = {}
	ls = []
	for i in range(n):
		(a, b) = [int(j) for j in input().split()]
		ls.append((a, b))
		d1[a] = d1.get(a, 0) + 1
		d2[b] = d2.get(b, 0) + 1
	ans = n * (n - 1) * (n - 2) // 6
	for (i, j) in ls:
		ans -= (d1[i] - 1) * (d2[j] - 1)
	print(ans)


import sys
input = sys.stdin.readline
for _ in range(int(input().strip())):
	n = int(input().strip())
	e = []
	d1 = {}
	d2 = {}
	for _ in range(n):
		(a, b) = map(int, input().strip().split(' '))
		e.append((a, b))
		if a not in d1:
			d1[a] = 0
		if b not in d2:
			d2[b] = 0
		d1[a] += 1
		d2[b] += 1
	o = n * (n - 1) * (n - 2) // 6
	for (i, j) in e:
		o -= (d1[i] - 1) * (d2[j] - 1)
	print(o)


import collections
t = int(input())
while t:
	n = int(input())
	a = []
	b = []
	freqa = [0] * (n + 1)
	freqb = [0] * (n + 1)
	for i in range(n):
		(x, y) = map(int, input().split())
		a.append(x)
		b.append(y)
		freqa[x] += 1
		freqb[y] += 1
	answer = n * (n - 1) * (n - 2) // 6
	for i in range(n):
		answer = answer - (freqa[a[i]] - 1) * (freqb[b[i]] - 1)
	print(answer)
	t = t - 1


from math import *
from collections import *
import sys
input = sys.stdin.readline

def inp():
	return int(input())

def st():
	return input().rstrip('\n')

def lis():
	return list(map(int, input().split()))

def ma():
	return map(int, input().split())
t = inp()
while t:
	t -= 1
	n = inp()
	topic = {}
	diff = {}
	res = n * (n - 1) * (n - 2) // 6
	r = []
	for i in range(n):
		(a, b) = ma()
		r.append([a, b])
		try:
			topic[a].append(b)
		except:
			topic[a] = [b]
		try:
			diff[b].append(a)
		except:
			diff[b] = [a]
	ex = 0
	store = {}
	vis = set()
	for i in range(n):
		z = r[i][0]
		if z in vis:
			continue
		vis.add(z)
		if len(topic[z]) <= 1:
			continue
		for j in range(len(topic[z])):
			curdiff = topic[z][j]
			if len(diff[curdiff]) <= 1:
				continue
			fi = len(topic[z]) - 1
			pro = len(diff[curdiff]) - 1
			res -= pro * fi
	print(res)


from math import comb
from collections import defaultdict
for _ in range(int(input())):
	n = int(input())
	d = defaultdict(list)
	sec = defaultdict(int)
	for i in range(n):
		(a, b) = map(int, input().split())
		d[a].append(b)
		sec[b] += 1
	ans = comb(n, 3)
	for x in d.keys():
		for i in d[x]:
			ans -= (len(d[x]) - 1) * (sec[i] - 1)
	print(ans)


for _ in range(int(input())):
	n = int(input())
	ans = n * (n - 1) * (n - 2) / 6
	td = []
	(t, d) = ({}, {})
	for i in range(n):
		(a, b) = map(int, input().split())
		td.append([a, b])
		if a not in t:
			t[a] = 1
		else:
			t[a] += 1
		if b not in d:
			d[b] = 1
		else:
			d[b] += 1
	for i in td:
		topic = i[0]
		difficulty = i[1]
		ans -= (t[topic] - 1) * (d[difficulty] - 1)
	ans = int(ans)
	print(ans)


from sys import stdin
input = stdin.readline
for _ in range(int(input())):
	n = int(input())
	(a, b) = (dict(), dict())
	res = n * (n - 1) * (n - 2) // 6
	xy = []
	for _ in range(n):
		(x, y) = map(int, input().split())
		if x in a.keys():
			a[x] += 1
		else:
			a[x] = 1
		if y in b.keys():
			b[y] += 1
		else:
			b[y] = 1
		xy.append([x, y])
	for (x, y) in xy:
		res -= (a[x] - 1) * (b[y] - 1)
	print(res)


from collections import deque, defaultdict
for _ in range(int(input())):
	n = int(input())
	a = []
	d1 = defaultdict(list)
	d2 = defaultdict(list)
	for i in range(n):
		(x, y) = map(int, input().split())
		d1[x].append(y)
		d2[y].append(x)
	ans = n * (n - 1) * (n - 2) // 6
	for i in d1:
		s = len(d1[i])
		for u in d1[i]:
			cnt = len(d2[u]) - 1
			ans -= cnt * (s - 1)
	print(ans)


t = int(input())
while t:
	t -= 1
	n = int(input())
	a = [0] * (n + 1)
	b = [0] * (n + 1)
	ca = [0] * (n + 1)
	cb = [0] * (n + 1)
	for i in range(1, n + 1):
		(x, y) = map(int, input().split())
		a[i] = x
		b[i] = y
		ca[a[i]] += 1
		cb[b[i]] += 1
	ans = n * (n - 1) * (n - 2) // 6
	for i in range(1, n + 1):
		ans -= (ca[a[i]] - 1) * (cb[b[i]] - 1)
	print(ans)


import sys
input = sys.stdin.readline

def main():
	N = int(input())
	AD = {}
	BD = {}
	AB = []
	for _ in range(N):
		(A, B) = map(int, input().split())
		AB.append((A, B))
		if A in AD:
			AD[A] += 1
		else:
			AD[A] = 1
		if B in BD:
			BD[B] += 1
		else:
			BD[B] = 1
	Ans = N * (N - 1) * (N - 2) // 6
	for (A, B) in AB:
		Ans -= (AD[A] - 1) * (BD[B] - 1)
	print(Ans)
T = int(input())
for _ in range(T):
	main()


import sys
input = sys.stdin.readline
from collections import Counter
t = int(input())
for tests in range(t):
	n = int(input())
	A = [tuple(map(int, input().split())) for i in range(n)]
	C1 = Counter()
	C2 = Counter()
	for (x, y) in A:
		C1[x] += 1
		C2[y] += 1
	ANS = 0
	for (a, b) in A:
		ANS += (C1[a] - 1) * (C2[b] - 1)
	print(n * (n - 1) * (n - 2) // 6 - ANS)


from sys import stdin
for i in range(int(stdin.readline())):
	a = int(stdin.readline())
	t1 = []
	d1 = []
	for i in range(a):
		(t, d) = map(int, stdin.readline().split())
		t1.append(t)
		d1.append(d)
	count = a * (a - 1) * (a - 2) // 6
	p = {}
	q = {}
	for i in range(a):
		if t1[i] not in p:
			p[t1[i]] = 1
		else:
			p[t1[i]] += 1
		if d1[i] not in q:
			q[d1[i]] = 1
		else:
			q[d1[i]] += 1
	count1 = 0
	for i in range(len(t1)):
		count1 += (p[t1[i]] - 1) * (q[d1[i]] - 1)
	print(count - count1)


import sys
input = sys.stdin.readline
for t in range(int(input())):
	n = int(input())
	val = n * (n - 1) * (n - 2) // 6
	arr = [[] for i in range(n)]
	t = [[] for i in range(n)]
	for i in range(n):
		(a, b) = map(int, input().split())
		a -= 1
		b -= 1
		arr[a].append(b)
		t[b].append(a)
	for i in range(n):
		for j in t[i]:
			val -= (len(t[i]) - 1) * (len(arr[j]) - 1)
	print(val)


import sys
input = sys.stdin.buffer.readline
t = int(input())
for _ in range(t):
	n = int(input())
	info = [list(map(int, input().split())) for i in range(n)]
	cnta = {}
	cntb = {}
	ans = 0
	for (a, b) in info:
		cnta[a] = cnta.get(a, 0) + 1
		cntb[b] = cntb.get(b, 0) + 1
	for (a, b) in info:
		ca = cnta.get(a, 0) - 1
		cb = cntb.get(b, 0) - 1
		ans += ca * cb
	print(n * (n - 1) * (n - 2) // 6 - ans)


t = int(input())
while t > 0:
	t -= 1
	n = int(input())
	topic_count = [0] * (n + 1)
	diff_count = [0] * (n + 1)
	x = [0] * n
	y = [0] * n
	result = n * (n - 1) * (n - 2) // 6
	for i in range(n):
		inputs = input().split()
		(x[i], y[i]) = (int(inputs[0]), int(inputs[1]))
		topic_count[x[i]] += 1
		diff_count[y[i]] += 1
	for i in range(n):
		result -= (topic_count[x[i]] - 1) * (diff_count[y[i]] - 1)
	print(result)


import decimal
import heapq
import math
import os
import sys
from collections import Counter, deque
from io import BytesIO, IOBase
import bisect
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')

def ints_get():
	return map(int, input().strip().split())

def list_get():
	return list(map(int, sys.stdin.readline().strip().split()))

def chars_get():
	return list(map(str, sys.stdin.readline().strip().split()))

def output(to_be_printed, end='\n'):
	sys.stdout.write(str(to_be_printed) + end)

def ipn():
	return int(input())

def main():
	for _ in range(ipn()):
		n = ipn()
		d1 = {}
		d2 = {}
		for _ in range(n):
			(a, b) = ints_get()
			if a not in d1:
				d1[a] = [b]
			else:
				d1[a].append(b)
			if b not in d2:
				d2[b] = 1
			else:
				d2[b] += 1
		val = n * (n - 1) * (n - 2) // 6
		for i in d1:
			for j in range(len(d1[i])):
				d1[i][j] = d2[d1[i][j]] - 1
		for i in d1:
			val -= sum(d1[i]) * (len(d1[i]) - 1)
		if val > 0:
			output(val)
		else:
			output(0)
	return
main()


from collections import defaultdict, deque, Counter
from heapq import heapify, heappop, heappush
import math
from copy import deepcopy
from itertools import combinations, permutations, product, combinations_with_replacement
from bisect import bisect_left, bisect_right
import sys

def input():
	return sys.stdin.readline().rstrip()

def getN():
	return int(input())

def getNM():
	return map(int, input().split())

def getList():
	return list(map(int, input().split()))

def getListGraph():
	return list(map(lambda x: int(x) - 1, input().split()))

def getArray(intn):
	return [int(input()) for i in range(intn)]
mod = 10 ** 9 + 7
MOD = 998244353
inf = float('inf')
eps = 10 ** (-10)
dy = [0, 1, 0, -1]
dx = [1, 0, -1, 0]
T = getN()
for i in range(T):
	N = getN()
	a_cnt = [0] * (N + 1)
	b_cnt = [0] * (N + 1)
	B = []
	for i in range(N):
		(a, b) = getNM()
		a_cnt[a] += 1
		b_cnt[b] += 1
		B.append([a, b])
	all = N * (N - 1) * (N - 2) // 6
	cap = 0
	for i in range(N):
		cap += (a_cnt[B[i][0]] - 1) * (b_cnt[B[i][1]] - 1)
	print(all - cap)


from sys import stdin
input = stdin.readline

def nc3(n):
	return n * (n - 1) * (n - 2) // 6

def answer():
	ans = nc3(n)
	sub = 0
	for i in range(n):
		(a, b) = x[i]
		sub += (d1[a] - 1) * (d2[b] - 1)
	return ans - sub
for T in range(int(input())):
	n = int(input())
	x = []
	(d1, d2) = (dict(), dict())
	for i in range(n):
		(a, b) = map(int, input().split())
		d1[a] = d1.get(a, 0) + 1
		d2[b] = d2.get(b, 0) + 1
		x.append([a, b])
	print(answer())


t = int(input())
for _ in range(t):
	first = {}
	second = {}
	ii = []
	n = int(input())
	for i in range(n):
		(a, b) = map(int, input().split())
		if a in first:
			first[a] += 1
		else:
			first[a] = 1
		if b in second:
			second[b] += 1
		else:
			second[b] = 1
		ii.append([a, b])
	res = n * (n - 1) * (n - 2) // 6
	v = 0
	for i in ii:
		v += (first[i[0]] - 1) * (second[i[1]] - 1)
	print(res - v)


import traceback
import os
import sys
from io import BytesIO, IOBase
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
sys.stdin = IOWrapper(sys.stdin)
input = lambda : sys.stdin.readline().rstrip('\r\n')

class SortedList:

	def __init__(self, iterable=[], _load=200):
		values = sorted(iterable)
		self._len = _len = len(values)
		self._load = _load
		self._lists = _lists = [values[i:i + _load] for i in range(0, _len, _load)]
		self._list_lens = [len(_list) for _list in _lists]
		self._mins = [_list[0] for _list in _lists]
		self._fen_tree = []
		self._rebuild = True

	def _fen_build(self):
		self._fen_tree[:] = self._list_lens
		_fen_tree = self._fen_tree
		for i in range(len(_fen_tree)):
			if i | i + 1 < len(_fen_tree):
				_fen_tree[i | i + 1] += _fen_tree[i]
		self._rebuild = False

	def _fen_update(self, index, value):
		if not self._rebuild:
			_fen_tree = self._fen_tree
			while index < len(_fen_tree):
				_fen_tree[index] += value
				index |= index + 1

	def _fen_query(self, end):
		if self._rebuild:
			self._fen_build()
		_fen_tree = self._fen_tree
		x = 0
		while end:
			x += _fen_tree[end - 1]
			end &= end - 1
		return x

	def _fen_findkth(self, k):
		_list_lens = self._list_lens
		if k < _list_lens[0]:
			return (0, k)
		if k >= self._len - _list_lens[-1]:
			return (len(_list_lens) - 1, k + _list_lens[-1] - self._len)
		if self._rebuild:
			self._fen_build()
		_fen_tree = self._fen_tree
		idx = -1
		for d in reversed(range(len(_fen_tree).bit_length())):
			right_idx = idx + (1 << d)
			if right_idx < len(_fen_tree) and k >= _fen_tree[right_idx]:
				idx = right_idx
				k -= _fen_tree[idx]
		return (idx + 1, k)

	def _delete(self, pos, idx):
		_lists = self._lists
		_mins = self._mins
		_list_lens = self._list_lens
		self._len -= 1
		self._fen_update(pos, -1)
		del _lists[pos][idx]
		_list_lens[pos] -= 1
		if _list_lens[pos]:
			_mins[pos] = _lists[pos][0]
		else:
			del _lists[pos]
			del _list_lens[pos]
			del _mins[pos]
			self._rebuild = True

	def _loc_left(self, value):
		if not self._len:
			return (0, 0)
		_lists = self._lists
		_mins = self._mins
		(lo, pos) = (-1, len(_lists) - 1)
		while lo + 1 < pos:
			mi = lo + pos >> 1
			if value <= _mins[mi]:
				pos = mi
			else:
				lo = mi
		if pos and value <= _lists[pos - 1][-1]:
			pos -= 1
		_list = _lists[pos]
		(lo, idx) = (-1, len(_list))
		while lo + 1 < idx:
			mi = lo + idx >> 1
			if value <= _list[mi]:
				idx = mi
			else:
				lo = mi
		return (pos, idx)

	def _loc_right(self, value):
		if not self._len:
			return (0, 0)
		_lists = self._lists
		_mins = self._mins
		(pos, hi) = (0, len(_lists))
		while pos + 1 < hi:
			mi = pos + hi >> 1
			if value < _mins[mi]:
				hi = mi
			else:
				pos = mi
		_list = _lists[pos]
		(lo, idx) = (-1, len(_list))
		while lo + 1 < idx:
			mi = lo + idx >> 1
			if value < _list[mi]:
				idx = mi
			else:
				lo = mi
		return (pos, idx)

	def add(self, value):
		_load = self._load
		_lists = self._lists
		_mins = self._mins
		_list_lens = self._list_lens
		self._len += 1
		if _lists:
			(pos, idx) = self._loc_right(value)
			self._fen_update(pos, 1)
			_list = _lists[pos]
			_list.insert(idx, value)
			_list_lens[pos] += 1
			_mins[pos] = _list[0]
			if _load + _load < len(_list):
				_lists.insert(pos + 1, _list[_load:])
				_list_lens.insert(pos + 1, len(_list) - _load)
				_mins.insert(pos + 1, _list[_load])
				_list_lens[pos] = _load
				del _list[_load:]
				self._rebuild = True
		else:
			_lists.append([value])
			_mins.append(value)
			_list_lens.append(1)
			self._rebuild = True

	def discard(self, value):
		_lists = self._lists
		if _lists:
			(pos, idx) = self._loc_right(value)
			if idx and _lists[pos][idx - 1] == value:
				self._delete(pos, idx - 1)

	def remove(self, value):
		_len = self._len
		self.discard(value)
		if _len == self._len:
			raise ValueError('{0!r} not in list'.format(value))

	def pop(self, index=-1):
		(pos, idx) = self._fen_findkth(self._len + index if index < 0 else index)
		value = self._lists[pos][idx]
		self._delete(pos, idx)
		return value

	def bisect_left(self, value):
		(pos, idx) = self._loc_left(value)
		return self._fen_query(pos) + idx

	def bisect_right(self, value):
		(pos, idx) = self._loc_right(value)
		return self._fen_query(pos) + idx

	def count(self, value):
		return self.bisect_right(value) - self.bisect_left(value)

	def __len__(self):
		return self._len

	def __getitem__(self, index):
		(pos, idx) = self._fen_findkth(self._len + index if index < 0 else index)
		return self._lists[pos][idx]

	def __delitem__(self, index):
		(pos, idx) = self._fen_findkth(self._len + index if index < 0 else index)
		self._delete(pos, idx)

	def __contains__(self, value):
		_lists = self._lists
		if _lists:
			(pos, idx) = self._loc_left(value)
			return idx < len(_lists[pos]) and _lists[pos][idx] == value
		return False

	def __iter__(self):
		return (value for _list in self._lists for value in _list)

	def __reversed__(self):
		return (value for _list in reversed(self._lists) for value in reversed(_list))

	def __repr__(self):
		return 'SortedList({0})'.format(list(self))
import math
from collections import defaultdict as dfd, defaultdict, Counter, deque
from functools import lru_cache
from itertools import accumulate
from heapq import *
import bisect

def geti():
	return int(input())

def gets():
	return input()

def getil():
	return list(map(int, input().split()))

def getsl():
	return input().split()

def getinps(s):
	inps = s.split()
	m = {'i': geti, 's': gets, 'il': getil, 'sl': getsl}
	if len(inps) == 1:
		return m[s]()
	return [m[k]() for k in inps]

def get2d(nrows, ncols, n=0):
	return [[n] * ncols for r in range(nrows)]

def get_acc(a):
	return list(accumulate(a))

def get_ncr(n, r, mod=10 ** 9 + 7):
	num = den = 1
	r = min(r, n - r)
	for i in range(r):
		num = num * (n - i) % mod
		den = den * (i + 1) % mod
	return num * pow(den, mod - 2, mod) % mod

def get_nc2(n):
	return n * (n - 1) // 2

def get_npr(n, r):
	if n < r:
		return 0
	return math.factorial(n) // math.factorial(r)

def put(a):
	return ' '.join(map(str, a))
ALPHABETS = 'abcdefghijklmnopqrstuvwxyz'
VOWELS = 'aeiou'
CONSONANTS = 'bcdfghjklmnpqrstvwxyz'
inf = float('inf')
mod = 10 ** 9 + 7

class Solution:

	def main(self):
		(N,) = getil()
		a = []
		b = []
		cnts1 = Counter()
		cnts2 = Counter()
		for _ in range(N):
			(t, d) = getil()
			a.append(t)
			b.append(d)
			cnts1[t] += 1
			cnts2[d] += 1
		ans = N * (N - 1) * (N - 2) // 6
		for i in range(N):
			(t, d) = (a[i], b[i])
			(x, y) = (cnts1[t], cnts2[d])
			ans -= (x - 1) * (y - 1)
		return ans
try:
	Sol = Solution()
	Test = geti()
	for Case in range(Test):
		ans = Sol.main()
		if ans is not None:
			print(ans)
except Exception as e:
	print(e)
	traceback.print_exc()


for _ in range(int(input())):
	n = int(input())
	(d1, d2) = ({}, {})
	l = []
	for i in range(n):
		(x, y) = map(int, input().split())
		if x in d1:
			d1[x] += 1
		else:
			d1[x] = 1
		if y in d2:
			d2[y] += 1
		else:
			d2[y] = 1
		l.append([x, y])
	ans = n * (n - 1) * (n - 2) // 6
	for i in range(n):
		ans -= (d1[l[i][0]] - 1) * (d2[l[i][1]] - 1)
	print(ans)


import sys
from bisect import bisect_right as lb
from collections import deque
from queue import PriorityQueue as pq
from math import gcd
input_ = lambda : sys.stdin.readline().strip('\r\n')
ii = lambda : int(input_())
il = lambda : list(map(int, input_().split()))
ilf = lambda : list(map(float, input_().split()))
lii = lambda : list(map(int, list(ip())))
ip = lambda : input_()
fi = lambda : float(input_())
ap = lambda ab, bc, cd: ab[bc].append(cd)
li = lambda : list(input_())
pr = lambda x: print(x)
prinT = lambda x: print(x)
f = lambda : sys.stdout.flush()
inv = lambda x: pow(x, mod - 2, mod)
mod = 10 ** 9 + 7
mod1 = 998244353
for _ in range(ii()):
	n = ii()
	(a, b, d, d1) = ([], [], {}, {})
	for i in range(n):
		(x, y) = il()
		a.append(x)
		b.append(y)
		d[x] = d.get(x, 0) + 1
		d1[y] = d1.get(y, 0) + 1
	ans = n * (n - 1) * (n - 2) // 6
	for i in range(n):
		ans -= (d[a[i]] - 1) * (d1[b[i]] - 1)
	print(ans)


t = int(input())
for _ in range(t):
	n = int(input())
	Topic = []
	Diff = []
	for i in range(n):
		(a, b) = map(int, input().split())
		Topic.append(a)
		Diff.append(b)
	T_map = dict.fromkeys(Topic, 0)
	D_map = dict.fromkeys(Diff, 0)
	for i in Topic:
		T_map[i] += 1
	for i in Diff:
		D_map[i] += 1
	good_trip = int(n * (n - 1) * (n - 2) / 6)
	bad_trip = 0
	for i in range(n):
		bad_trip += (T_map[Topic[i]] - 1) * (D_map[Diff[i]] - 1)
	print(good_trip - bad_trip)


import enum
import random
import collections
import string
import math
import copy
import os
import sys
from io import BytesIO, IOBase
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))

def input():
	return sys.stdin.readline().rstrip('\r\n')
mo = int(1000000000.0 + 7)

def exgcd(a, b):
	if not b:
		return (1, 0)
	(y, x) = exgcd(b, a % b)
	y -= a // b * x
	return (x, y)

def getinv(a, m):
	(x, y) = exgcd(a, m)
	return -1 if x == 1 else x % m

def comb(n, b):
	res = 1
	b = min(b, n - b)
	for i in range(b):
		res = res * (n - i) / (i + 1)
	return res

def quickpower(a, n):
	res = 1
	while n:
		if n & 1:
			res = res * a % mo
		n >>= 1
		a = a * a % mo
	return res

def dis(a, b):
	return abs(a[0] - b[0]) + abs(a[1] - b[1])

def getpref(x):
	if x > 1:
		return x * (x - 1) >> 1
	else:
		return 0

def orafli(upp):
	primes = []
	marked = [False for i in range(upp + 3)]
	prvs = [i for i in range(upp + 3)]
	for i in range(2, upp):
		if not marked[i]:
			primes.append(i)
		for j in primes:
			if i * j >= upp:
				break
			marked[i * j] = True
			prvs[i * j] = j
			if i % j == 0:
				break
	return (primes, prvs)

def lower_ord(c: str) -> int:
	return ord(c) - 97

def upper_ord(c: str) -> int:
	return ord(c) - 65

def read_list():
	return [int(i) for i in input().split()]

def read_int():
	s = input().split()
	if len(s) == 1:
		return int(s[0])
	else:
		return map(int, s)

def ask(s, i, j):
	print(f'{s} {i} {j}', flush=True)

def answer(x):
	print(f'finish {x}', flush=True)
import functools
import itertools
from fractions import Fraction
import random

def lowbit(x):
	return -x & x

def pref(x):
	return x * (x + 1) >> 1

def cum(sx, mx):
	return (sx + mx) * (mx - sx + 1) >> 1

def solve():
	n = read_int()
	E = []
	D1 = {}
	D2 = {}
	for i in range(n):
		(x, y) = read_int()
		D1.setdefault(x, []).append(y)
		D2.setdefault(y, []).append(x)
		E.append((x, y))
	ans = n * (n - 1) * (n - 2) // 3 // 2
	dans = 0
	for (x, y) in E:
		dans += (len(D1[x]) - 1) * (len(D2[y]) - 1)
	print(ans - dans)
T = int(input())
for ti in range(T):
	solve()


inf = float('inf')
import sys
import pprint
import logging
from logging import getLogger
import array

def input():
	return sys.stdin.readline().rstrip('\r\n')

def maps():
	return [int(i) for i in input().split()]
logging.basicConfig(format='%(message)s', level=logging.WARNING)
logger = getLogger(__name__)
logger.setLevel(logging.INFO)

def debug(msg, *args):
	logger.info(f'{msg}={pprint.pformat(args)}')
from collections import Counter, defaultdict
for i in range(*maps()):
	(n,) = maps()
	A = []
	(da, db) = (defaultdict(int), defaultdict(int))
	for __ in range(n):
		(a, b) = maps()
		da[a] += 1
		db[b] += 1
		A.append((a, b))
	tot = n * (n - 1) * (n - 2) // 6
	for (a, b) in A:
		tot -= (da[a] - 1) * (db[b] - 1)
	print(tot)


from sys import stdin
input = stdin.readline
for _ in range(int(input())):
	n = int(input())
	(a, b) = (dict(), dict())
	res = n * (n - 1) * (n - 2) // 6
	xy = []
	for _ in range(n):
		(x, y) = map(int, input().split())
		try:
			a[x] += 1
		except:
			a[x] = 1
		try:
			b[y] += 1
		except:
			b[y] = 1
		xy.append([x, y])
	for (x, y) in xy:
		res -= (a[x] - 1) * (b[y] - 1)
	print(res)


from math import factorial as f

def comb(n, m):
	if m > n:
		return 0
	if m == n:
		return 1
	i = n - m
	r = n
	for j in range(i + 1, n):
		r *= j
	return r / f(m)
t = int(input())
for _ in range(0, t):
	n = int(input())
	v = [[0, 0] for i in range(0, n)]
	d1 = dict()
	d2 = dict()
	for i in range(0, n):
		(a, b) = map(int, input().split())
		v[i] = [a, b]
		if d1.get(a) == None:
			d1[a] = 1
		else:
			d1[a] += 1
		if d2.get(b) == None:
			d2[b] = 1
		else:
			d2[b] += 1
	result = comb(n, 3)
	for i in range(0, n):
		(a, b) = v[i]
		if d1[a] > 1 and d2[b] > 1:
			result -= (d1[a] - 1) * (d2[b] - 1)
	print('%.0f' % result)


import collections
import sys
input = sys.stdin.readline
for _ in range(int(input())):
	n = int(input())
	mat = []
	x = collections.defaultdict(int)
	y = collections.defaultdict(int)
	for i in range(n):
		(a, b) = map(int, input().split())
		x[a] += 1
		y[b] += 1
		mat.append([a, b])
	ans = n * (n - 1) * (n - 2) // 6
	for i in range(n):
		ans -= (x[mat[i][0]] - 1) * (y[mat[i][1]] - 1)
	print(ans)


import sys
import collections
input = sys.stdin.readline

def solve():
	n = int(input())
	p = [list(map(int, input().split())) for _ in range(n)]
	a = collections.Counter((x for (x, _) in p))
	b = collections.Counter((x for (_, x) in p))
	ans = n * (n - 1) * (n - 2) // 6
	for (i, j) in p:
		ans -= (a[i] - 1) * (b[j] - 1)
	print(ans)
for _ in range(int(input())):
	solve()


import sys
import re
if len(sys.argv) > 1 and re.match(re.compile('^t[0-9]$'), sys.argv[1]):
	import os
	sys.stdin = open(os.path.join(os.path.dirname(os.path.abspath(__file__)), sys.argv[1]), 'r')
t = int(input())
for _ in range(t):
	n = int(input())
	(ca, cb) = ([0] * (n + 1), [0] * (n + 1))
	s = []
	for _ in range(n):
		(xa, xb) = map(int, input().split())
		ca[xa] += 1
		cb[xb] += 1
		s += [(xa, xb)]
	tc = n * (n - 1) * (n - 2) // 6
	for a in s:
		tc -= (ca[a[0]] - 1) * (cb[a[1]] - 1)
	print(tc)


import os, sys
from io import BytesIO, IOBase
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
try:
	(sys.stdin, sys.stdout) = (open('in.txt', 'r'), open('out.txt', 'w'))
except:
	pass
ii1 = lambda : int(sys.stdin.readline().strip())
is1 = lambda : sys.stdin.readline().strip()
iia = lambda : list(map(int, sys.stdin.readline().strip().split()))
isa = lambda : sys.stdin.readline().strip().split()
mod = int(1000000000.0 + 7)
from collections import defaultdict as dd
from math import factorial

def ncr(N):
	return N * (N - 1) * (N - 2) // 6

def fact(N):
	return factorial(N)
for _ in range(ii1()):
	n = ii1()
	arr = []
	dic = dd(int)
	dic2 = dd(int)
	for _ in range(n):
		(s, d) = iia()
		arr.append((s, d))
		dic[s] += 1
		dic2[d] += 1
	ans1 = ncr(n)
	for (s, d) in arr:
		ans1 -= (dic[s] - 1) * (dic2[d] - 1)
	print(ans1)


from collections import defaultdict
for _ in range(int(input())):
	n = int(input())
	inp = []
	t = defaultdict(int)
	d = defaultdict(int)
	ans = n * (n - 1) * (n - 2) // 6
	for _ in range(n):
		(a, b) = map(int, input().split())
		inp.append([a, b])
		t[a] += 1
		d[b] += 1
	for i in range(n):
		(l, m) = inp[i]
		ans -= (t[l] - 1) * (d[m] - 1)
	print(ans)


from collections import Counter, defaultdict
m = int(input())

def solve(n: int, arr: list) -> None:
	cnt_x = defaultdict(int)
	cnt_y = defaultdict(int)
	for (x, y) in arr:
		cnt_x[x] += 1
		cnt_y[y] += 1
	ans = 0
	for (x, y) in arr:
		ans += (cnt_x[x] - 1) * (cnt_y[y] - 1)
	print(n * (n - 1) * (n - 2) // 6 - ans)
while m > 0:
	n = int(input())
	arr = list()
	for _ in range(n):
		a = input().split()
		arr.append((int(a[0]), int(a[1])))
	solve(n, arr)
	m -= 1


t = int(input())
for i in range(t):
	n = int(input())
	a = []
	b = []
	for i in range(n):
		(ai, bi) = map(int, input().split())
		ai -= 1
		bi -= 1
		a.append(ai)
		b.append(bi)
	ca = [0] * n
	cb = [0] * n
	for i in range(n):
		ca[a[i]] += 1
		cb[b[i]] += 1
	nn = 0
	for i in range(n):
		nn += (ca[a[i]] - 1) * (cb[b[i]] - 1)
	ans = n * (n - 1) * (n - 2) // 6
	print(ans - nn)


for _ in range(int(input())):
	n = int(input())
	ans = 0
	(c1, c2) = ([0] * (n + 1), [0] * (n + 1))
	pairs = []
	for i in range(n):
		(a, b) = map(int, input().split())
		c1[a] += 1
		c2[b] += 1
		pairs += [(a, b)]
	print(n * (n - 1) * (n - 2) // 6 - sum(((c1[a] - 1) * (c2[b] - 1) for (a, b) in pairs)))


import sys
input = sys.stdin.readline

def ncr(x):
	return x * (x - 1) * (x - 2) // 6
a = int(input())
from collections import *
for i in range(a):
	al = defaultdict(list)
	dl = defaultdict(list)
	mp = defaultdict(int)
	s = int(input())
	a1 = []
	for i in range(s):
		(x, y) = map(int, input().split())
		a1.append([x, y])
		al[x].append(y)
		dl[y].append(x)
		mp[y] += 1
	total = ncr(s)
	for i in al:
		t = al[i]
		for j in t:
			total -= (mp[j] - 1) * (len(t) - 1)
	print(total)


import sys
import bisect
from bisect import bisect_left as lb
from bisect import bisect_right as rb
input_ = lambda : sys.stdin.readline().strip('\r\n')
from math import log
from math import gcd
from math import atan2, acos
from random import randint
sa = lambda : input_()
sb = lambda : int(input_())
sc = lambda : input_().split()
sd = lambda : list(map(int, input_().split()))
sflo = lambda : list(map(float, input_().split()))
se = lambda : float(input_())
sf = lambda : list(input_())
flsh = lambda : sys.stdout.flush()
mod = 10 ** 9 + 7
mod1 = 998244353
gp = []
cost = []
dp = []
mx = []
ans1 = []
ans2 = []
special = []
specnode = []
a = 0
kthpar = []

def dfs2(root, par):
	if par != -1:
		dp[root] = dp[par] + 1
	for i in range(1, 20):
		if kthpar[root][i - 1] != -1:
			kthpar[root][i] = kthpar[kthpar[root][i - 1]][i - 1]
	for child in gp[root]:
		if child == par:
			continue
		kthpar[child][0] = root
		dfs(child, root)
ans = 0
a = []
(n, k) = (0, 0)
b = []
vis = []
tot = 0
time = []
time1 = []
adj = []
mx = -1
eps = 1e-07
x = 0
pref = []
lvl = []

def update_it(bit, i, val):
	n = len(bit)
	while i < n:
		bit[i] += val
		i += i & -i

def get_ans(bit, i):
	n = len(bit)
	tot = 0
	while i > 0:
		tot += bit[i]
		i -= i & -i
	return tot

def hnbhai(tc):
	n = sb()
	a = []
	b = []
	x = {}
	y = {}
	for i in range(n):
		t = sd()
		a.append(t[0])
		b.append(t[1])
		x[a[-1]] = x.get(a[-1], 0) + 1
		y[b[-1]] = y.get(b[-1], 0) + 1
	tot = n * (n - 1) * (n - 2) // 6
	for i in range(n):
		tot -= (x[a[i]] - 1) * (y[b[i]] - 1)
	print(tot)
for _ in range(sb()):
	hnbhai(_ + 1)


from __future__ import division, print_function
from collections import defaultdict, deque
import heapq
import os
import copy
import sys
from io import BytesIO, IOBase
from typing import Counter, DefaultDict, Deque, OrderedDict
import bisect, math, time
if sys.version_info[0] < 3:
	from __builtin__ import xrange as range
	from future_builtins import ascii, filter, hex, map, oct, zip
from math import ceil, log2
MOD = 1000000007

def power(x, y):
	if y == 0:
		return 1
	if x == 0:
		return 0
	temp = power(x, y // 2)
	if y % 2 == 0:
		return temp * temp % MOD
	else:
		return x * temp * temp % MOD

def RightAngled(a, n):
	xpoints = defaultdict(lambda : 0)
	ypoints = defaultdict(lambda : 0)
	for i in range(n):
		xpoints[a[i][0]] += 1
		ypoints[a[i][1]] += 1
	count = 0
	for i in range(n):
		if xpoints[a[i][0]] >= 1 and ypoints[a[i][1]] >= 1:
			count += (xpoints[a[i][0]] - 1) * (ypoints[a[i][1]] - 1)
	return count

def main():
	t = int(input())
	while t:
		n = int(input())
		points = []
		for _ in range(n):
			(x, y) = map(int, input().split())
			points.append([x, y])
		ncr = n * (n - 1) * (n - 2) // (3 * 2)
		cnt = RightAngled(points, n)
		print(ncr - cnt)
		t -= 1
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')

def print(*args, **kwargs):
	(sep, file) = (kwargs.pop('sep', ' '), kwargs.pop('file', sys.stdout))
	at_start = True
	for x in args:
		if not at_start:
			file.write(sep)
		file.write(str(x))
		at_start = False
	file.write(kwargs.pop('end', '\n'))
	if kwargs.pop('flush', False):
		file.flush()
if sys.version_info[0] < 3:
	(sys.stdin, sys.stdout) = (FastIO(sys.stdin), FastIO(sys.stdout))
else:
	(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')
main()


import sys
input = sys.stdin.readline
for _ in range(int(input())):
	n = int(input())
	x = {}
	y = {}
	l = []
	for i in range(n):
		(a, b) = map(int, input().split())
		l.append((a, b))
		if a in x:
			x[a] += 1
		else:
			x[a] = 1
		if b in y:
			y[b] += 1
		else:
			y[b] = 1
	ans = n * (n - 1) * (n - 2) // 6
	cnt = 0
	for i in l:
		(a, b) = (i[0], i[1])
		ca = x[a] - 1
		cb = y[b] - 1
		cnt += ca * cb
	sys.stdout.write(str(ans - cnt) + '\n')


t = int(input())
for _ in range(t):
	n = int(input())
	rows = [0] * n
	cols = [0] * n
	counts = {}
	for i in range(n):
		(a, b) = map(int, input().split())
		rows[a - 1] += 1
		cols[b - 1] += 1
		if (a - 1, b - 1) in counts:
			counts[a - 1, b - 1] += 1
		else:
			counts[a - 1, b - 1] = 1
	total = n * (n - 1) * (n - 2) // 6
	for guy in counts:
		(x, y) = guy
		a = counts[guy]
		total -= a * (a - 1) * (a - 2) // 6
		total -= a * (a - 1) * (n - a) // 2
		total -= a * (rows[x] - a) * (cols[y] - a)
	print(total)


import sys
LI = lambda : list(map(int, sys.stdin.readline().split()))
MI = lambda : map(int, sys.stdin.readline().split())
SI = lambda : sys.stdin.readline().strip('\n')
II = lambda : int(sys.stdin.readline())
for _ in range(II()):
	n = II()
	a = {}
	b = {}
	s = []
	for i in range(n):
		(x, y) = MI()
		s.append((x, y))
		a[x] = a.get(x, 0) + 1
		b[y] = b.get(y, 0) + 1
	ans = n * (n - 1) * (n - 2) // 6
	for i in range(n):
		ans -= (a[s[i][0]] - 1) * (b[s[i][1]] - 1)
	print(ans)


import sys
sys.setrecursionlimit(10 ** 7)
input = sys.stdin.readline
I = lambda : int(input())
RI = lambda : map(int, input().split())
RL = lambda : list(map(int, input().split()))
RS = lambda : set(map(int, input().split()))
RT = lambda : tuple(map(int, input().split()))
RLN = lambda n: [list(map(int, input().split())) for _ in range(n)]
RSN = lambda n: [set(map(int, input().split())) for _ in range(n)]
INF = 10 ** 18
EPS = 10 ** (-9)
import collections

def solve():
	n = I()
	p = RLN(n)
	a = collections.Counter((x for (x, _) in p))
	b = collections.Counter((x for (_, x) in p))
	ans = n * (n - 1) * (n - 2) // 6
	for (i, j) in p:
		ans -= (a[i] - 1) * (b[j] - 1)
	print(ans)
for _ in range(int(input())):
	solve()


def main():
	alpha = 'abcdefghijklmnopqrstuvwxyz'
	ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
	inf = 1e+17
	mod = 10 ** 9 + 7

	def factorial(n):
		f = 1
		for i in range(1, n + 1):
			f = f * i % mod
		return f

	def ncr(n, r):
		num = den = 1
		for i in range(r):
			num = num * (n - i) % mod
			den = den * (i + 1) % mod
		return num * pow(den, mod - 2, mod) % mod

	def solve(n, a, b):
		atob = dict()
		btoa = dict()
		for i in range(n):
			if a[i] in atob:
				atob[a[i]].add(b[i])
			else:
				atob[a[i]] = {b[i]}
			if b[i] in btoa:
				btoa[b[i]].add(a[i])
			else:
				btoa[b[i]] = {a[i]}
		cnt = 0
		for ele in atob:
			for x in atob[ele]:
				cnt += (len(btoa[x]) - 1) * (len(atob[ele]) - 1)
		return n * (n - 1) * (n - 2) // 6 - cnt
	t = int(input())
	ans = []
	for _ in range(t):
		n = int(input())
		a = []
		b = []
		for i in range(n):
			s = [int(x) for x in input().split()]
			a.append(s[0])
			b.append(s[1])
		ans.append(solve(n, a, b))
	p = 1
	for answer in ans:
		print(answer)
		p += 1
import sys, threading
import bisect
import math
import itertools
from sys import stdout
import heapq
from queue import PriorityQueue
from collections import deque
input = sys.stdin.readline
thread = threading.Thread(target=main)
thread.start()
thread.join()


from sys import *
from collections import *
input = stdin.readline
for u in range(int(input())):
	n = int(input())
	(l, d) = (defaultdict(int), defaultdict(list))
	for i in range(n):
		(a, b) = map(int, input().split())
		l[b] += 1
		d[a].append(b)
	ans = n * (n - 2) * (n - 1) // 6
	for i in d:
		for j in d[i]:
			ans -= (len(d[i]) - 1) * (l[j] - 1)
	print(ans)


from typing import DefaultDict
from sys import stdin
read = stdin.readline
for _ in range(int(read())):
	n = int(read())
	adic = DefaultDict(lambda : 0)
	bdic = DefaultDict(lambda : 0)
	stuff = []
	for i in range(n):
		(a, b) = map(int, read().split())
		adic[a] += 1
		bdic[b] += 1
		stuff.append((a, b))
	total = n * (n - 1) * (n - 2) // 6
	for (a, b) in stuff:
		total -= (adic[a] - 1) * (bdic[b] - 1)
	print(total)


x = int(input())
for q in range(x):
	y = int(input())
	a = []
	a0 = [0 for i in range(y)]
	a1 = [0 for i in range(y)]
	for i in range(y):
		a.append(list(map(int, input().split())))
		a0[a[i][0] - 1] += 1
		a1[a[i][1] - 1] += 1
	ans = y * (y - 1) * (y - 2) // 6
	for i in range(y):
		ans = ans - (a0[a[i][0] - 1] - 1) * (a1[a[i][1] - 1] - 1)
	print(ans)


from collections import defaultdict
from sys import stdin, stdout

def input():
	return stdin.readline().strip()

def read_int_list():
	return list(map(int, input().split()))

def read_int_tuple():
	return tuple(map(int, input().split()))

def read_int():
	return int(input())
t = int(input())
for i in range(1, t + 1):
	n = int(input())
	t_dict = defaultdict(int)
	d_dict = defaultdict(int)
	qns = []
	for _ in range(n):
		(t, d) = read_int_tuple()
		t_dict[t] += 1
		d_dict[d] += 1
		qns.append((t, d))
	t_d_dict = defaultdict(int)
	d_t_dict = defaultdict(int)
	for qn in qns:
		(t, d) = qn
		t_d_dict[t] += d_dict[d]
		d_t_dict[d] += t_dict[t]
	res = n * (n - 1) * (n - 2) // 6
	accum = 0
	for qn in qns:
		(t, d) = qn
		n_t = t_dict[t] - 1
		n_d = d_dict[d] - 1
		n_t_d = t_d_dict[t] - d_dict[d]
		n_d_t = d_t_dict[d] - t_dict[t]
		accum += n_t * d_dict[d] - 2 * n_t + n_t_d
		accum += n_d * t_dict[t] - 2 * n_d + n_d_t
	print(res - accum // 4)


for _ in range(int(input())):
	n = int(input())
	(a, b) = ([], [])
	counta = [-1] * (n + 1)
	countb = [-1] * (n + 1)
	for _ in range(n):
		(x, y) = map(int, input().strip().split())
		a.append(x)
		b.append(y)
		counta[x] += 1
		countb[y] += 1
	ans = n * (n - 1) * (n - 2) // 6
	for i in range(n):
		ans -= counta[a[i]] * countb[b[i]]
	print(ans)


import os, sys
from io import BytesIO, IOBase
from math import log2, ceil, sqrt, gcd
from _collections import deque
import heapq as hp
from bisect import bisect_left, bisect_right
from math import cos, sin
from itertools import permutations
from operator import itemgetter
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')
mod = 10 ** 9 + 7

def solve(x):
	d = dict()
	for i in b[x]:
		d[i] = d.get(i, 0) + 1
	ck = [d[i] for i in d]
	if len(ck) < 3:
		return 0
	m = len(ck)
	dp = [[0] * m for _ in range(3)]
	dp[0][0] = ck[0]
	for i in range(1, len(ck)):
		dp[0][i] = dp[0][i - 1] + ck[i]
	for i in range(1, 3):
		for j in range(i, m):
			dp[i][j] = dp[i][j - 1] + dp[i - 1][j - 1] * ck[j]
	print(dp[-1][-1], '->')
	return dp[-1][-1]
for _ in range(int(input())):
	n = int(input())
	a = [[] for _ in range(n + 1)]
	b = [[] for _ in range(n + 1)]
	d = dict()
	for _ in range(n):
		(x, y) = map(int, input().split())
		a[x].append(y)
		b[y].append(x)
		d[y] = d.get(y, 0) + 1
	ans = 0
	for i in range(1, n + 1):
		t = len(a[i])
		ct = 0
		for i in a[i]:
			ct += d[i] - 1
		ans += ct * max(t - 1, 0)
	print(n * (n - 1) * (n - 2) // 6 - ans)


from collections import defaultdict

def func():
	dic1 = defaultdict(int)
	dic2 = defaultdict(int)
	for i in range(n):
		dic1[problems[i][0]] += 1
		dic2[problems[i][1]] += 1
	ans = n * (n - 1) * (n - 2) // 6
	for i in range(n):
		ans -= (dic1[problems[i][0]] - 1) * (dic2[problems[i][1]] - 1)
	print(ans)
for _ in range(int(input())):
	n = int(input())
	problems = [list(map(int, input().split())) for __ in range(n)]
	func()


import sys
import os.path
from collections import *
import math
import bisect
import heapq as hq
from fractions import Fraction
from random import randint
if os.path.exists('input.txt'):
	sys.stdin = open('input.txt', 'r')
	sys.stdout = open('output.txt', 'w')
input = sys.stdin.readline

def solve():
	n = int(input())
	h1 = Counter()
	h2 = Counter()
	arr = [0 for i in range(n)]
	res = 0
	for i in range(n):
		arr[i] = [int(x) for x in input().split()]
		h1[arr[i][0]] += 1
		h2[arr[i][1]] += 1
	m = n
	for i in range(n):
		(x, y) = arr[i]
		z = (h1[x] - 1) * (h2[y] - 1)
		res += z
	res = n * (n - 1) * (n - 2) // 6 - res
	print(res)
t = int(input())
while t:
	t -= 1
	solve()


def naiveSolve():
	return

def solve():
	return

def main():
	t = int(input())
	allans = []
	for _ in range(t):
		n = int(input())
		a = []
		b = []
		aCnt = [0] * (n + 1)
		bCnt = [0] * (n + 1)
		for __ in range(n):
			(aa, bb) = readIntArr()
			a.append(aa)
			b.append(bb)
			aCnt[aa] += 1
			bCnt[bb] += 1
		ans = n * (n - 1) * (n - 2) // 6
		badCnts = 0
		for i in range(n):
			badCnts += (aCnt[a[i]] - 1) * (bCnt[b[i]] - 1)
		ans -= badCnts
		allans.append(ans)
	multiLineArrayPrint(allans)
	return
import sys
input = sys.stdin.buffer.readline

def oneLineArrayPrint(arr):
	print(' '.join([str(x) for x in arr]))

def multiLineArrayPrint(arr):
	print('\n'.join([str(x) for x in arr]))

def multiLineArrayOfArraysPrint(arr):
	print('\n'.join([' '.join([str(x) for x in y]) for y in arr]))

def readIntArr():
	return [int(x) for x in input().split()]

def makeArr(defaultValFactory, dimensionArr):
	dv = defaultValFactory
	da = dimensionArr
	if len(da) == 1:
		return [dv() for _ in range(da[0])]
	else:
		return [makeArr(dv, da[1:]) for _ in range(da[0])]

def queryInteractive(x, y):
	print('? {} {}'.format(x, y))
	sys.stdout.flush()
	return int(input())

def answerInteractive(i1, j1, i2, j2):
	print('! {} {} {} {}'.format(i1, j1, i2, j2))
	sys.stdout.flush()
inf = float('inf')
from math import gcd, floor, ceil
for _abc in range(1):
	main()


from collections import defaultdict
import sys
input = sys.stdin.buffer.readline

def inp():
	return int(input())

def input_gen_list():
	return input().split()

def input_list():
	return list(map(int, input().split()))

def input_string():
	s = input()
	return list(s[:len(s) - 1])

def input_int_gen():
	return map(int, input().decode().split())
from collections import defaultdict
tests = inp()
for _ in range(tests):
	n = inp()
	xs = [0 for _ in range(n + 1)]
	ys = [0 for _ in range(n + 1)]
	points = []
	for _ in range(n):
		(a, b) = input_int_gen()
		points.append((a, b))
		xs[a] += 1
		ys[b] += 1
	res = 0
	for (a, b) in points:
		res += (xs[a] - 1) * (ys[b] - 1)
	print(n * (n - 1) * (n - 2) // 6 - res)


def solve():
	n = int(input())
	arr = [list(map(int, input().split())) for i in range(n)]
	a = [-1] * (n + 1)
	b = [-1] * (n + 1)
	for i in range(n):
		a[arr[i][0]] += 1
		b[arr[i][1]] += 1
	ans = 0
	for (x, y) in arr:
		ans += a[x] * b[y]
	return n * (n - 1) * (n - 2) // 6 - ans
import sys
input = lambda : sys.stdin.readline().rstrip()
t = int(input())
for i in range(t):
	print(solve())


def solve():
	n = int(input())
	arr = []
	a = [0] * (n + 1)
	b = [0] * (n + 1)
	for i in range(n):
		(x, y) = map(int, input().split())
		arr.append((x, y))
		a[x] += 1
		b[y] += 1
	res = (n - 2) * (n - 1) * n // 6
	for i in range(n):
		(x, y) = arr[i]
		res -= (a[x] - 1) * (b[y] - 1)
	print(res)
q = int(input())
for _ in range(q):
	solve()


def nc3(n):
	if n < 3:
		return 0
	return n * (n - 1) * (n - 2) // 6

def nc2(n):
	if n < 2:
		return 0
	return n * (n - 1) // 2
for _ in range(int(input())):
	n = int(input())
	x = {}
	y = {}
	l = []
	for i in range(n):
		(a, b) = map(int, input().split())
		if a in x:
			x[a] += 1
		else:
			x[a] = 1
		if b in y:
			y[b] += 1
		else:
			y[b] = 1
		l.append([a, b])
	ans = nc3(n)
	for (a, b) in l:
		ans -= (x[a] - 1) * (y[b] - 1)
	print(ans)


import sys
from collections import Counter
input = sys.stdin.readline

def solve():
	n = int(input())
	a = [-1] * n
	b = [-1] * n
	prefA = Counter()
	prefB = Counter()
	suffA = Counter()
	suffB = Counter()
	for i in range(n):
		(x, y) = map(int, input().split())
		a[i] = x
		b[i] = y
		suffA[x] += 1
		suffB[y] += 1
	bad = 0
	for i in range(n):
		suffA[a[i]] -= 1
		suffB[b[i]] -= 1
		case1 = prefA[a[i]] * suffB[b[i]]
		case2 = suffA[a[i]] * suffB[b[i]]
		case3 = suffA[a[i]] * prefB[b[i]]
		case4 = prefA[a[i]] * prefB[b[i]]
		bad += case1 + case2 + case3 + case4
		prefA[a[i]] += 1
		prefB[b[i]] += 1
	ans = n * (n - 1) * (n - 2) // 6 - bad
	print(ans)
for nt in range(int(input())):
	solve()


t = int(input())
for _ in range(t):
	n = int(input())
	A = []
	B = []
	c1 = [0] * (n + 1)
	d1 = [0] * (n + 1)
	for i in range(n):
		(a, b) = map(int, input().split())
		A.append(a)
		B.append(b)
		c1[a] += 1
		d1[b] += 1
	ans = n * (n - 1) * (n - 2) // 6
	for i in range(n):
		ans -= (c1[A[i]] - 1) * (d1[B[i]] - 1)
	print(ans)