description: 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 ≤ t ≤ 50000) — the number of testcases.
  
  The first line of each testcase contains an integer n (3 ≤ n ≤ 2 ⋅ 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 ≤ a_i, b_i ≤ 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 ⋅ 10^5.
  
  Output
  
  Print the number of ways to select three training problems that meet either of the requirements described in the statement.
  
  Example
  
  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.
solution: import java.io.IOException;
  import java.io.InputStream;
  import java.io.PrintWriter; // System.out is a PrintStream
  import java.util.HashMap;
  import java.util.InputMismatchException;
  
  
  public class D {
      private static int MOD = (int)1e9 + 7, mod = 99_82_44_353;
      private static double PI = 3.14159265358979323846;
  
      public static void main(String[] args) throws IOException {
          FasterScanner scn = new FasterScanner();
          PrintWriter out = new PrintWriter(System.out);
          for (int tc = scn.nextInt(); tc > 0; tc--) {
              int N = scn.nextInt();
              int[][] arr = new int[N][2];
              HashMap<Integer, Integer> x = new HashMap<>(), y = new HashMap<>();
              for (int i = 0; i < N; i++) {
                  arr[i][0] = scn.nextInt();
                  arr[i][1] = scn.nextInt();
                  x.put(arr[i][0], x.getOrDefault(arr[i][0], 0) + 1);
                  y.put(arr[i][1], y.getOrDefault(arr[i][1], 0) + 1);
              }
              long ans = 1L * N * (N - 1) * (N - 2) / 6L;
              for (int i = 0; i < N; i++) {
                  ans -= 1L * (x.get(arr[i][0]) - 1) * (y.get(arr[i][1]) - 1);
              }
              out.println(ans);
          }
          out.close();
      }
  
      /* ------------------- Sorting ------------------- */
      private static void ruffleSort(int[] arr) {
          // int N = arr.length;
          // Random rand = new Random();
          // for (int i = 0; i < N; i++) {
          //     int oi = rand.nextInt(N), temp = arr[i];
          //     arr[i] = arr[oi];
          //     arr[oi] = temp;
          // }
          // Arrays.sort(arr);
      }
          
      /* ------------------- Sorting ------------------- */
      
      private static boolean isPalindrome(String str) {
          for (int i = 0, j = str.length() - 1; i < j; i++, j--) {
              if (str.charAt(i) != str.charAt(j)) {
                  return false;
              }
          }
          return true;
      }
      
      private static boolean isPalindrome(char[] str) {
          for (int i = 0, j = str.length - 1; i < j; i++, j--) {
              if (str[i] != str[j]) {
                  return false;
              }
          }
          return true;
      }
      
      /* ------------------- Pair class ------------------- */
      private static class Pair implements Comparable<Pair> {
  		int x, y;
  		Pair(int x, int y) {
  			this.x = x;
  			this.y = y;
  		}
  		public int compareTo(Pair o) {
  			return this.x == o.x ? this.y - o.y : this.x - o.x;
  		}
  	}
  
      /* ------------------- HCF and LCM ------------------- */
      private static int gcd(int num1, int num2) {
          int temp = 0;
          while (num2 != 0) {
              temp = num1;
              num1 = num2;
              num2 = temp % num2;
          }
          return num1;
      }
      
      private static int lcm(int num1, int num2) {
          return (int)((1L * num1 * num2) / gcd(num1, num2));
      }
      
      /* ------------------- primes and prime factorization ------------------- */
      private static boolean[] seive(int N) {
          // true means not prime, false means is a prime number :)
          boolean[] notPrimes = new boolean[N + 1];
          notPrimes[0] = notPrimes[1] = true;
          for (int i = 2; i * i <= N; i++) {
              if (notPrimes[i]) continue;
              for (int j = i * i; j <= N; j += i) {
                  notPrimes[j] = true;
              }
          }
          return notPrimes;
      }
  
  	/*
      private static TreeMap<Integer, Integer> primeFactors(long N) {
  		TreeMap<Integer, Integer> primeFact = new TreeMap<>();
  		for (int i = 2; i <= Math.sqrt(N); i++) {
              int count = 0;
              while (N % i == 0) {
                  N /= i;
                  count++;
              }
              if (count != 0) {
                  primeFact.put(i, count);
              }
  		}
  		if (N != 1) {
              primeFact.put((int)N, 1);
          }
  		return primeFact;
  	}
      */
  
      /* ------------------- Binary Search ------------------- */
      private static long factorial(int N) {
          long ans = 1L;
          for (int i = 2; i <= N; i++) {
              ans *= i;
          }
          return ans;
      }
  
      private static long[] factorialDP(int N) {
          long[] factDP = new long[N + 1];
          factDP[0] = factDP[1] = 1;
          for (int i = 2; i <= N; i++) {
              factDP[i] = factDP[i - 1] * i;
          }
          return factDP;
      }
  
      private static long factorialMod(int N, int mod) {
          long ans = 1L;
          for (int i = 2; i <= N; i++) {
              ans = ((ans % mod) * (i % mod)) % mod;
          }
          return ans;
      }
  
      /* ------------------- Binary Search ------------------- */
      private static int floorSearch(int[] arr, int st, int ed, int tar) {
          int ans = -1;
          while (st <= ed) {
              int mid = ((ed - st) >> 1) + st;
              if (arr[mid] <= tar) {
                  ans = mid;
                  st = mid + 1;
              } else {
                  ed = mid - 1;
              }
          }
          return ans;
      }
      
      private static int ceilingSearch(int[] arr, int st, int ed, int tar) {
          int ans = -1;
          while (st <= ed) {
              int mid = ((ed - st) >> 1) + st;
              if (arr[mid] < tar) {
                  st = mid + 1;
              } else {
                  ans = mid;
                  ed = mid - 1;
              }
          }
          return ans;
      }
      
      /* ------------------- Power Function ------------------- */
      public static long pow(long x, long y) {
          long res = 1;
  		while (y > 0) {
              if ((y & 1) != 0) {
                  res = (res * x);
  				y--;
  			}
  			x = (x * x);
  			y >>= 1;
  		}
  		return res;
  	}
      
  	public static long powMod(long x, long y, int mod) {
          long res = 1;
  		while (y > 0) {
              if ((y & 1) != 0) {
                  res = (res * x) % mod;
  				y--;
  			}
  			x = (x * x) % mod;
  			y >>= 1;
  		}
  		return res % mod;
  	}
  
      /* ------------------- Disjoint Set(Union and Find) ------------------- */
      private static class DSU {
  		public int[] parent, rank;
  		DSU(int N) {
  			parent = new int[N];
  			rank = new int[N];
  			for (int i = 0; i < N; i++) {
  				parent[i] = i;
                  rank[i] = 1;
              }
  		}
  		public int find(int a) {
  			if (parent[a] == a) {
  				return a;
              }
              return parent[a] = find(parent[a]);
  		}
  		public boolean union(int a, int b) {
  			int parA = find(a), parB = find(b);
  			if (parA == parB) return false;
  			if (rank[parA] > rank[parB]) {
                  parent[parB] = parA;
              } else if (rank[parA] < rank[parB]) {
                  parent[parA] = parB;
              } else {
                  parent[parA] = parB;
                  rank[parB]++;
              }
              return true;
  		}
  	}
      
      /* ------------------- Scanner class for input ------------------- */
      
      private static class FasterScanner {
  		private InputStream stream;
  		private byte[] buffer = new byte[1024];
  		private int curChar, numChars;
  		private SpaceCharFilter filter;
  
  		public FasterScanner() {
              // default
  			this.stream = System.in;
  		}
  
  		public FasterScanner(InputStream stream) {
  			this.stream = stream;
  		}
  
  		private int readChar() {
  			if (numChars == -1) {
  				throw new InputMismatchException();
              }
  			if (curChar >= numChars) {
  				curChar = 0;
  				try {
  					numChars = stream.read(buffer);
  				} catch (IOException e) {
  					throw new InputMismatchException(e.getMessage());
  				}
  				if (numChars <= 0) {
  					return -1;
                  }
  			}
  			return buffer[curChar++];
  		}
  
  		private boolean isWhiteSpace(int c) {
  			if (filter != null) {
  				return filter.isWhiteSpace(c);
              }
  			return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
  		}
  
  		private boolean isNewLine(int ch) {
  			if (filter != null) {
  				return filter.isNewLine(ch);
              }
  			return ch == '\r' || ch == '\n' || ch == -1;
  		}
  
          public char nextChar() {
              int ch = readChar();
              char res = '\0';
              while (isWhiteSpace(ch)) {
                  ch = readChar();
              }
              do {
                  res = (char)ch;
                  ch = readChar();
              } while (!isWhiteSpace(ch));
              return res;
          }
  
  		public String next() {
  			int ch = readChar();
              StringBuilder res = new StringBuilder();
  			while (isWhiteSpace(ch)) {
  				ch = readChar();
              }
  			do {
  				res.appendCodePoint(ch);
  				ch = readChar();
  			} while (!isWhiteSpace(ch));
  			return res.toString();
  		}
  
  		public String nextLine() {
  			int ch = readChar();
              StringBuilder res = new StringBuilder();
  			do {
  				res.appendCodePoint(ch);
  				ch = readChar();
  			} while (!isNewLine(ch));
  			return res.toString();
  		}
  
  		public int nextInt() {
  			int ch = -1, sgn = 1, res = 0;
              do {
                  ch = readChar();
              } while (isWhiteSpace(ch));
  			if (ch == '-') {
  				sgn = -1;
  				ch = readChar();
  			}
  			do {
  				if (ch < '0' || ch > '9') {
  					throw new InputMismatchException("not a number");
                  }
  				res = (res * 10) + (ch - '0');
  				ch = readChar();
  			} while (!isWhiteSpace(ch));
              
  			return res * sgn;
  		}
  
  		public long nextLong() {
  			int ch = -1, sgn = 1;
              long res = 0L;
              do {
                  ch = readChar();
              } while (isWhiteSpace(ch));
  			if (ch == '-') {
  				sgn = -1;
  				ch = readChar();
  			}
  			do {
  				if (ch < '0' || ch > '9') {
  					throw new InputMismatchException("not a number");
                  }
  				res = (10L * res) + (ch - '0');
  				ch = readChar();
  			} while (!isWhiteSpace(ch));
  
  			return 1L * res * sgn;
  		}
  
          public double nextDouble() {
              return Double.parseDouble(next());
          }
  
          /* for custom delimiters */
  		public interface SpaceCharFilter {
  			public boolean isWhiteSpace(int ch);
  			public boolean isNewLine(int ch);
  		}
  	}
  }
  