//===
template<class Monoid>
struct DynamicSegmentTree {
    using T = typename Monoid::value_type;
    using llong = long long;

    struct Node {
        Node *left, *right;
        T v;
        Node(T v):v(v), left(nullptr), right(nullptr) {};
    };

    Node *root = nullptr;
    llong L = 0, R = 0;

    DynamicSegmentTree() = default;

    inline void eval(Node &u) {
        T lv = Monoid::identity(), rv = Monoid::identity();
        if (u.left) lv = u.left->v;
        if (u.right) rv = u.right->v;
        u.v = Monoid::operation(lv, rv);
    };

    inline void expand(llong i) {
        if (L == R) {
            R++;
            while (i >= R) R += R - L;
            while (i < L) L -= R - L;
            root = new Node(Monoid::identity());
        }
        else {
            Node *tmp;
            while (i >= R) {
                R += R - L;
                tmp = new Node(root->v);
                tmp->left = root;
                root = tmp;
            }
            while (i < L) {
                L -= R - L;
                tmp = new Node(root->v);
                tmp->right = root;
                root = tmp;
            }
        }
    };

    inline void update(llong i, T v) {
        if (i < L || R <= i) expand(i);
        update(root, L, R, i, v);
    };

    void update(Node *node, llong nl, llong nr, llong k, T v) {
        if (nr - nl <= 1) {
            node->v = v;
            return;
        }

        llong mid = (nl + nr) / 2;
        if (k < mid) {
            if (!node->left) node->left = new Node(Monoid::identity());
            update(node->left, nl, (nl + nr) / 2, k, v);
        }
        else {
            if (!node->right) node->right = new Node(Monoid::identity());
            update(node->right, (nl + nr) / 2, nr, k, v);
        }

        eval(*node);
        return;
    }

    // [l, r)
    inline T fold(llong l, llong r) {
        if (l < L) expand(l);
        if (r > R) expand(r);
        return fold(root, L, R, l, r);
    };
    T fold(Node *node, llong nl, llong nr, llong ql, llong qr) {
        if (ql <= nl && nr <= qr) return node->v;

        T lv = Monoid::identity(), rv = Monoid::identity();
        llong mid = (nl + nr) / 2;
        if (node->left && ql < mid && nl < qr) {
            lv = fold(node->left, nl, mid, ql, qr);
        }
        if (node->right && ql < nr && mid < qr) {
            rv = fold(node->right, mid, nr, ql, qr);
        }

        return Monoid::operation(lv, rv);
    };
    
    T operator[] (const llong k) {
        return fold(k, k + 1);
    };
};
//===
#define _overload(_1, _2, _3, _4, name, ...) name
#define _rep1(Itr, N) _rep3(Itr, 0, N, 1)
#define _rep2(Itr, a, b) _rep3(Itr, a, b, 1)
#define _rep3(Itr, a, b, step) for (llong (Itr) = a; (Itr) < b; (Itr) += step)
#define repeat(...) _overload(__VA_ARGS__, _rep3, _rep2, _rep1)(__VA_ARGS__)

#include <iostream>
#include <vector>

using namespace std;
using llong = long long;

struct Monoid {
    using value_type = llong;

    static llong operation(llong a, llong b) { return a + b; };
    static llong identity() { return 0; };
};

DynamicSegmentTree<Monoid> sa;
DynamicSegmentTree<Monoid> sc;

int main() {
    llong n;
    cin >> n;
    vector<llong> a(n);
    vector<llong> b(n);
    vector<llong> c(n);

    for (auto &vs:a) cin >> vs;
    for (auto &vs:b) cin >> vs;
    for (auto &vs:c) cin >> vs;

    for (auto vs:a) sa.update(vs, sa[vs] + 1);
    for (auto vs:c) sc.update(vs, sc[vs] + 1);

    llong ans = 0;
    for (auto vs:b) {
        ans += sa.fold(0, vs) * sc.fold(vs + 1, 1ll << 50);
    }

    cout << ans << endl;

    return 0;
};


Measured memory_bytes: 95308