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 (GCC 5.4.1) (judge verdict: Runtime Error)

/*

Ver3
*/

#include <stdio.h>
#include <stdlib.h>

int A[100000];
int B[100000];
int C[100000];
int a[10000];
int c[10000];
int n;
int al, ar, cl, cr;

int result = -1;
int lb;
int ub;

int cmp(const void *p, const void *q) {
	return *(int*)p - *(int*)q;
}

int bin_search_ver2(int n, int array[], int left, int right, int value);

//#define DEBUG1
//#define DEBUG2
//#define DEBUGF

//#define DEBUGitti//評価１　A一致
//#define DEBUGfin//評価２　A不一致
//#define DEBUG_C_itti//評価１　入力例３の正解の確認

int main() {

	//評価１　A一致
#ifdef DEBUGitti
	n = 10;
	int A[10] = { 0,1,2,3,4,5,6,7,8,9 };
	int B[10] = { 0,1,2,3,4,5,6,7,8,9 };
	int Less_than(int n, int array[], int left, int right, int value);
	int y = Less_than(n, A, 1, 1, B[1]);
	printf("y = %d", y);
#endif
	//評価２　A不一致
#ifdef DEBUGfin
	n = 10;
	int A[10] = { 0,2,4,6,8,10,12,14,16,18 };
	int B[10] = { 0,1,2,3,4,5,6,7,8,9 };
	int Less_than(int n, int array[], int left, int right, int value);
	int y = Less_than(n, A, 0, 1, B[1]);
	printf("y = %d", y);
#endif
	//評価３　入力例３の正解の確認
#ifdef DEBUG_C_itti
	n = 6;
	int A[6] = { 2, 3, 6, 14, 53, 159 };
	int B[6] = { 6, 9, 58, 79, 84, 323 };
	int C[6] = { 2, 50, 79, 288, 383, 2643 };

	int left = 0;
	int right = 9;
	int Less_than(int n, int array[], int left, int right, int value);

	int c_tmp;
	int al = 0;
	int ar = n - 1;
	int cl = 0;
	int cr = n - 1;
	int total = 0;

	for (int i = 0; i < n; i++) {
		a[i] = Less_than(n, A, al, ar, B[i]);
		printf("a[%d]  = %d\n", i, a[i]);

		c[i] = Less_more(n, C, cl, cr, B[i]);
		printf("c[%d]  = %d\n", i, c[i]);

		total = total + (a[i] * c[i]);
		printf("total = %d\n", total);
		getch();
	}

#endif

	//int Less_than(int n, int array[], int left, int right, int value);
	//int Less_more(int n, int array[], int left, int right, int value);


	//入力作業
	scanf("%d", &n);
	for (int i = 0; i < n; i++) {
		scanf("%d", &A[i]);
	}
	for (int i = 0; i < n; i++) {
		scanf("%d", &B[i]);
	}
	for (int i = 0; i < n; i++) {
		scanf("%d", &C[i]);
	}

	//入力値の表示
#ifdef DEBUG1
	for (int i = 0; i < n; i++) {
		printf("A[%d] = %d\n", i, A[i]);
	}
	for (int i = 0; i < n; i++) {
		printf("B[%d] = %d\n", i, B[i]);
	}
	for (int i = 0; i < n; i++) {
		printf("C[%d] = %d\n", i, C[i]);
	}
	printf("\n");
#endif

	//ソート作業
	qsort((void *)A, n, sizeof(int), cmp);
	qsort((void *)B, n, sizeof(int), cmp);
	qsort((void *)C, n, sizeof(int), cmp);

	//ソート結果の表示
#ifdef DEBUG2
	for (int i = 0; i < n; i++) {
		printf("A[%d] = %d\n", i, A[i]);
	}
	for (int i = 0; i < n; i++) {
		printf("B[%d] = %d\n", i, B[i]);
	}
	for (int i = 0; i < n; i++) {
		printf("C[%d] = %d\n", i, C[i]);
	}
#endif

	//演算作業
	//その１　各要素数のカウントデータ収集作業

	//カウントデータ収集作業

	int al = 0;
	int ar = n - 1;
	int cl = 0;
	int cr = n - 1;
	int total = 0;

	for (int i = 0; i < n; i++) {
		bin_search_ver2(n, A, al, ar, B[i]);
		if (al <= lb || lb <= ar) {
			a[i] = lb + 1;
		}
		if(lb < al){
			a[i] = 0;
		}
		if (lb > ar) {
			a[i] = n;
		}
#ifdef DEBUGF
		printf("a[%d]  = %d\n", i, a[i]);
#endif

		c[i] = bin_search_ver2(n, C, cl, cr, B[i]);
		if (cl <= ub || ub <= cr) {
			c[i] = cr - ub;
		}
		if (ub < cl) {
			c[i] = cr + 1;
		}
		if (ub > cr) {
			c[i] = 0;
		}
#ifdef DEBUGF
		printf("c[%d]  = %d\n", i, c[i]);
#endif
		total = total + (a[i] * c[i]);
	}
#ifdef DEBUGF
	printf("total = %d\n", total);
	getch();
#endif
	printf("%d\n", total);
	//getch();
	return 0;
}


/*
関数の作成_Ver4
関数	：int bin_search_ver2(int array[], int left, int right, int value)
概要	：二分探索を実行する
入力値	：配列:array[], 開始イテレータ:left, 終了イテレータ:right, 探索データ:value
戻り値	：一致ありの場合：
一致イテレータが一つの場合：一致要素のイテレータを返す
一致イテレータが複数の場合：最初に検出した一致イテレータを返す
: match_l : 一致要素の最小イテレータ
: match_u : 一致要素の最大イテレータ
：lb : 以下になる最後の要素
：ub : 超える最初の要素
：一致無しの場合：-1を返す
：lb : 以下になる最後の要素のイテレータ
：ub : 超える最初の要素のイテレータ
要件	：配列:a[]は昇順に昇順ソート済である事
：left、right は前方向イテレータの要件を満たす事
*/

//#include <stdio.h>
//#include <stdlib.h>
//
//#define DEBUG1
//#define DEBUG2
//#define DEBUGF

#define DEBUGitti//評価１　一致
//#define DEBUGfin//評価２　不一致
//#define DEBUGitti_s//評価３　一致（開始位置変更）
//#define DEBUGfin_s//評価４　不一致（開始位置変更）
//#define DEBUGfout//評価５　不一致　範囲外
//#define DEBUGitti_s_min//評価６　一致（開始位置変更し要素数１）
//#define DEBUGitti_s_min１_err//評価７　一致（開始位置が終了位置超えているエラー）
//#define DEBUGitti_douiu_ari//評価８　一致（同一値複数あり）

//int main() {
//	int bin_search_ver2(int n, int array[], int left, int right, int value);
//
//	//評価１　一致
//#ifdef DEBUGitti
//	int n = 10;
//	int A[] = { 0,1,2,3,4,5,6,7,8,9 };
//	int B[] = { 0,5,9 };
//	int left = 0;
//	int right = n - 1;
//	int value = B[1];
//	int x = bin_search_ver2(n, A, left, right, value);
//#endif
//
//	//評価２　不一致
//#ifdef DEBUGfin
//	int n = 10;
//	int A[] = { 2,4,6,8,10,12,14,16,18,20 };
//	int B[] = { 3,13,19 };
//	int left = 0;
//	int right = n - 1;
//	int value = B[0];
//	int  x = bin_search_ver2(n, A, left, right, value);
//#endif
//
//	//評価３　一致（開始位置変更）
//#ifdef DEBUGitti_s
//	int n = 10;
//	int A[] = { 0,1,2,3,4,5,6,7,8,9 };
//	int B[] = { 0,5,9 };
//	int left = 0;
//	int right = n - 1;
//	int value = B[0];
//	int  x = bin_search_ver2(n, A, left, right, value);
//#endif
//
//	//評価４　不一致（開始位置変更）
//#ifdef DEBUGfin_s
//	int n = 10;
//	int A[] = { 2,4,6,8,10,12,14,16,18,20 };
//	int B[] = { 3,13,19 };
//	int left = 0;
//	int right = n - 1;
//	int value = B[0];
//	int  x = bin_search_ver2(n, A, left, right, value);
//#endif
//
//	//評価５　不一致　範囲外
//#ifdef DEBUGfout
//	int n = 10;
//	int A[] = { 2,4,6,8,10,12,14,16,18,20 };
//	int B[] = { 1,21 };
//	int left = 0;
//	int right = n - 1;
//	int value = B[0];
//	int  x = bin_search_ver2(n, A, left, right, value);
//#endif
//
//	//評価６　一致（開始位置変更し要素数１）
//#ifdef DEBUGitti_s_min
//	int n = 10;
//	int A[] = { 0,1,2,3,4,5,6,7,8,9 };
//	int B[] = { 0,5,9 };
//	int left = 9;
//	int right = n - 1;
//	int value = B[2];
//	int  x = bin_search_ver2(n, A, left, right, value);
//#endif
//
//	//評価７　一致（開始位置が終了位置超えているエラー）
//#ifdef DEBUGitti_s_min１_err
//	int n = 10;
//	int A[] = { 0,1,2,3,4,5,6,7,8,9 };
//	int B[] = { 0,5,9 };
//	int left = 10;
//	int right = n - 1;
//	int value = B[2];
//	int  x = bin_search_ver2(n, A, left, right, value);
//#endif
//
//	//評価８　一致（同一値複数あり）
//#ifdef DEBUGitti_douiu_ari
//	int n = 10;
//	int A[] = { 4,4,5,5,5,5,5,5,5,6 };
//	int B[] = { 0,5,9 };
//	int left = 0;
//	int right = n - 1;
//	int value = B[1];
//	int x = bin_search_ver2(n, A, left, right, value);
//#endif
//
//	printf("result = %d\n", x);
//
//	getch();
//	return 0;
//}
//

/*
関数	：int bin_search_ver2(int n, int array[], int left, int right, int value)
概要	：二分探索を実行する
入力値	：配列:array[], 開始イテレータ:left, 終了イテレータ:right, 探索データ:value
戻り値	：一致ありの場合：一致要素のイテレータを返す
：一致無しの場合：-1を返す
：lb : 以下になる最後の要素のイテレータ相当の数値（探索範囲( left - 1 ～ right + 1 ）
：ub : 超える最初の要素のイテレータ相当の数値（探索範囲( left - 1 ～ right + 1 ）
要件	：配列:a[]は昇順に昇順ソート済である事
：left、right は前方向イテレータの要件を満たす事
*/
int bin_search_ver2(int n, int array[], int left, int right, int value) {

	int flag_err = -1;
	//int result = -1;
	result = -1;
	int flag_end = -1;
	//int lb = left - 1;
	//int ub = right + 1;
	lb = left - 1;
	ub = right + 1;
	int mid;
	int mid_tmp = -2;
	int match_l = -2;
	int match_u = -2;

	//入力エラー検出
	if (left > right || right < 0 || left >(n - 1)) {//エラーチェック
		printf("%s\n", "探索範囲エラーです");
		flag_err = 1;//エラーフラグTrue
	}
	//if ((value > array[right]) || (value < array[left])) {//エラーチェック

	//	printf("array[right] = %d\n", array[right]);
	//	printf("array[left] = %d\n", array[left]);

	//	printf("%s\n", "このデータ内にはありません");
	//	flag_err = 1;//エラーフラグTrue
	//}
	//エラーでは無い場合
	if (flag_err != 1) {
#ifdef DEBUG1
		printf("value = %d\n", value);
#endif
		while ((ub - lb) > 1 && flag_end != 1) {
			mid = (ub + lb) / 2;
#ifdef DEBUG1
			printf("lb = %d\t mid = %d\t ub = %d\n", lb, mid, ub);
#endif
			if (array[mid] == value) {

				//lbを探索する
				mid_tmp = mid;

				while (array[mid_tmp] == value && mid_tmp >= left) {
					mid_tmp = mid_tmp - 1;
				}
				match_l = mid_tmp + 1;
				lb = mid_tmp;

				//ubを探索する
				mid_tmp = mid;

				while (array[mid_tmp] == value && mid_tmp <= right) {
					mid_tmp = mid_tmp + 1;
				}
				match_u = mid_tmp - 1;
				ub = mid_tmp;

#ifdef DEBUG1
				printf("array[%d]=%d == %d\n", mid, array[mid], value);
#endif
				result = mid;
				flag_end = 1;

			}
			if (array[mid] > value) {
#ifdef DEBUG1
				printf("array[%d]=%d > %d\n", mid, array[mid], value);
#endif
				ub = mid;
			}
			if (array[mid] < value) {
#ifdef DEBUG1
				printf("array[%d]=%d < %d\n", mid, array[mid], value);
#endif
				lb = mid;
			}
		}

		if (result < 0) {
#ifdef DEBUG2
			printf("%s\n", "二分探索 一致無し ");
			printf(" mid : 最後の探索要素　= %d\n", mid);
			printf(" lb : 以下になる最後の要素のイテレータ　= %d\n", lb);
			printf(" ub : 超えるになる最初の要素のイテレータ　= %d\n", ub);
#endif
		}
		else
		{
#ifdef DEBUG2
			printf("%s\n", "二分探索 一致有り");
			printf(" result : 最初に検出した位置要素のイテレータ　= %d\n", result);
			printf(" match_l: 一致要素の最小イテレータ　= %d\n", match_l);
			printf(" match_u: 一致要素の最大イテレータ　= %d\n", match_u);
			printf(" lb : 以下になる最後の要素のイテレータ　= %d\n", lb);
			printf(" ub : 超えるになる最初の要素のイテレータ　= %d\n", ub);
#endif
		}
	}
	return result;
}