Problem:
Score : 300 points

Problem Statement

The season for Snuke Festival has come again this year. First of all, Ringo will perform a ritual to summon Snuke. For the ritual, he needs an altar, which consists of three parts, one in each of the three categories: upper, middle and lower.

He has N parts for each of the three categories. The size of the i-th upper part is A_i, the size of the i-th middle part is B_i, and the size of the i-th lower part is C_i.

To build an altar, the size of the middle part must be strictly greater than that of the upper part, and the size of the lower part must be strictly greater than that of the middle part. On the other hand, any three parts that satisfy these conditions can be combined to form an altar.

How many different altars can Ringo build? Here, two altars are considered different when at least one of the three parts used is different.

Constraints

1 \leq N \leq 10^5

1 \leq A_i \leq 10^9(1\leq i\leq N)

1 \leq B_i \leq 10^9(1\leq i\leq N)

1 \leq C_i \leq 10^9(1\leq i\leq N)

All input values are integers.

Input

Input is given from Standard Input in the following format:

N
A_1 ... A_N
B_1 ... B_N
C_1 ... C_N

Output

Print the number of different altars that Ringo can build.

Sample Input 1

2
1 5
2 4
3 6

Sample Output 1

3

The following three altars can be built:

Upper: 1-st part, Middle: 1-st part, Lower: 1-st part

Upper: 1-st part, Middle: 1-st part, Lower: 2-nd part

Upper: 1-st part, Middle: 2-nd part, Lower: 2-nd part

Sample Input 2

3
1 1 1
2 2 2
3 3 3

Sample Output 2

27

Sample Input 3

6
3 14 159 2 6 53
58 9 79 323 84 6
2643 383 2 79 50 288

Sample Output 3

87

Solution in C# (Mono-mcs 6.8.0.105) (judge verdict: Wrong Answer)

using System;
using System.Collections;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Threading.Tasks;

/*
・概要（計算量はO(logN)：Nは要素数）
二分探索を行い、lower_boundないしupper_boundを返す。
lower_boundは、指定した値以上になる最初のインデックスを返す。（a <= b）
upper_boundは、指定した値より大きくなる最初のインデックスを返す。（a < b）

なお、配列・リストの最大値よりも大きい値をtargetとした場合、
要素数（＝最終インデックス + 1）を返すので、out of rangeに注意。

namespace BinarySearch内にある以下のクラスのstaticメソッドを使用。
即ち、
リストの場合はclass Listに、配列の場合はclass Arrayに、それぞれアクセスし、
当該クラス内のLowerBoundないしUpperBoundメソッドを使用する。


・使用法（リストの場合の例）
1. 当然だが、使用前にソート
2. 対象となるリストと値を、それぞれの関数に渡し、インデックスを取得する

e.g. intリストの場合
//元のリスト
List<int> intLs = new List<int>(intArr);
//ターゲット
int target = int.Parse(Console.ReadLine());
//lower_bound
int lowLs = BinarySearch.List.LowerBound<int>(intLs, target);
//upper_bound
int upLs = BinarySearch.List.UpperBound<int>(intLs, target);

*/


class Program
{
	//Main
	static void Main(string[] args)
	{
		//読み込む
		int N = int.Parse(Console.ReadLine());
		int[] An = Console.ReadLine().Split(' ').Select(i => int.Parse(i)).ToArray();
		int[] Bn = Console.ReadLine().Split(' ').Select(i => int.Parse(i)).ToArray();
		int[] Cn = Console.ReadLine().Split(' ').Select(i => int.Parse(i)).ToArray();

		//ソート
		Array.Sort(An);
		Array.Sort(Bn);
		Array.Sort(Cn);

		//各Bnに対して、組み合わせることができるCnの個数を記憶
		int[] CforB = new int[N];
		for(int i=0; i<N; i++){
			//Biの対象となる最小のCi
			int indC = BinarySearch.Array.UpperBound<int>(Cn, Bn[i]);
			//組める相手がいない場合、終了
			if(indC >= N){
				break;
			}

			//それ以上のCiとは全てペアを組むことが可能
			CforB[i] = N-indC;
		}

		//iでペアを組める場合、i-1でもペアを組めるので、逆順の累積和にしておく
		for(int i=N-1; i>0; i--){
			CforB[i-1] += CforB[i];
		}

		//AnとセットにできるBnを確認し、それぞれとセットにできるCnの数を加算
		int ans = 0;
		for(int i=0; i<N; i++){
			//中部の対象
			int indB = BinarySearch.Array.UpperBound<int>(Bn, An[i]);
			//組める相手がいない場合、終了
			if(indB >= N){
				break;
			}

			//当該Bn以上と組めるCnの総数を加算
			ans += CforB[indB];
		}

		//出力
		Console.WriteLine(ans);
	}
}


/*
二分探索用の名前空間
*/
namespace BinarySearch{
	//対象が配列の場合
	class Array
	{
		//LowerBound
		/*
		引数は、対象の配列と、対象の値
		当該値以上になる最初のインデックスを返す
		*/
		public static int LowerBound<T>(T[] arr, T target)
			where T : IComparable
		{
			//長さを取得
			int len = arr.Length;

			//両端を初期化
			int max = len-1;
			int min = 0;

			//二分探索（条件を満たすまで探索）
			while(max >= min){
				//中央を更新
				int mid = min + (max-min)/2;

				//midより大きい場合（target > arr[mid]）
				/*
				cf. ここがLowerとUpperとの違い
				*/
				if(target.CompareTo(arr[mid]) > 0){
						min = mid + 1;
				}
				//小さい場合
				else{
						max = mid - 1;
				}
			}

			//target以上となる最初のインデックスを出力
			return min;
		}

		//UpperBound
		/*
		引数は、対象の配列と、対象の値
		当該値より大きくなる最初のインデックスを返す
		*/
		public static int UpperBound<T>(T[] arr, T target)
			where T : IComparable
		{
			//長さを取得
			int len = arr.Length;

			//両端を初期化
			int max = len-1;
			int min = 0;

			//二分探索（条件を満たすまで探索）
			while(max >= min){
				//中央を更新
				int mid = min + (max-min)/2;

				//mid以上の場合（target >= arr[mid]）
				/*
				cf. ここがLowerとUpperとの違い
				*/
				if(target.CompareTo(arr[mid]) >= 0){
						min = mid + 1;
				}
				//小さい場合
				else{
						max = mid - 1;
				}
			}

			//targetより大きくなる最初のインデックスを出力
			return min;
		}
	}

	//対象がリストの場合
	class List{
		//LowerBound
		/*
		引数は、対象のリストと、対象の値
		当該値以上になる最初のインデックスを返す
		*/
		public static int LowerBound<T>(List<T> list, T target)
			where T : IComparable
		{
			//長さを取得
			int len = list.Count();

			//両端を初期化
			int max = len-1;
			int min = 0;

			//二分探索（条件を満たすまで探索）
			while(max >= min){
				//中央を更新
				int mid = min + (max-min)/2;

				//midより大きい場合（target > list[mid]）
				/*
				cf. ここがLowerとUpperとの違い
				*/
				if(target.CompareTo(list[mid]) > 0){
						min = mid + 1;
				}
				//小さい場合
				else{
						max = mid - 1;
				}
			}

			//target以上となる最初のインデックスを出力
			return min;
		}

		//UpperBound
		/*
		引数は、対象のリストと、対象の値
		当該値より大きくなる最初のインデックスを返す
		*/
		public static int UpperBound<T>(List<T> list, T target)
			where T : IComparable
		{
			//長さを取得
			int len = list.Count();

			//両端を初期化
			int max = len-1;
			int min = 0;

			//二分探索（条件を満たすまで探索）
			while(max >= min){
				//中央を更新
				int mid = min + (max-min)/2;

				//mid以上の場合（target >= list[mid]）
				/*
				cf. ここがLowerとUpperとの違い
				*/
				if(target.CompareTo(list[mid]) >= 0){
						min = mid + 1;
				}
				//小さい場合
				else{
						max = mid - 1;
				}
			}

			//targetより大きくなる最初のインデックスを出力
			return min;
		}
	}
}