#include <iostream>
#include <vector>
#include <set>
#include <tuple>

using namespace std;

typedef long long ll;

const int MOD = 998244353;

struct Modint {
  ll val;
  
  Modint (ll _val = 0)
    : val(_val % MOD) {}

  Modint operator+ (Modint other) const {
    return Modint(val + other.val);
  }

  void operator+= (Modint other) {
    val += other.val;
    val %= MOD;
  }

  Modint operator- () const {
    return Modint(MOD - val);
  }

  Modint operator- (Modint other) const {
    return Modint(val + MOD - other.val);
  }

  void operator-= (Modint other) {
    val += MOD - other.val;
    val %= MOD;
  }

  Modint operator* (Modint other) const {
    return Modint(val * other.val);
  }

  void operator*= (Modint other) {
    val *= other.val;
    val %= MOD;
  }

  bool operator== (Modint other) const {
    return val == other.val;
  }

  bool operator!= (Modint other) const {
    return val != other.val;
  }
};

Modint exp (Modint a, int k) {
  if (k == 0) {
    return Modint(1);
  } else if (k % 2 == 0) {
    Modint half = exp(a, k / 2);
    return half * half;
  } else {
    return a * exp(a, k - 1);
  }
}

Modint inv (Modint a) {
  return exp(a, MOD - 2);
}

ostream& operator<< (ostream& out, Modint p) {
  out << p.val;
  return out;
}

const int MAX_N = 1 << 17;

int mex (const vector<int> &v) {
  set<int> sp;
  for (int i = 0; i < (int) v.size() + 1; i++) {
    sp.insert(i);
  }

  for (auto u : v) {
    sp.erase(u);
  }

  return *sp.begin();
}

Modint p1e18 [MAX_N];

class Graph {
  int n;
  vector<vector<int>> adj;

public:
  Graph (int _n) : n(_n), adj(vector<vector<int>> (n + 1, vector<int> (0))) {}

  void add_edge (int u, int v) {
    if (u > v) swap(u, v);
    adj[u].push_back(v);
  }

  vector<Modint> summary () {
    vector<int> grundy (n + 1);
    for (int u = n; u >= 1; u--) {
      vector<int> v;
      for (int nxt : adj[u]) {
        v.push_back(grundy[nxt]);
      }
      grundy[u] = mex(v);
    }

    vector<Modint> ans (MAX_N, Modint(0));
    for (int u = 1; u <= n; u++) {
      ans[grundy[u]] += p1e18[u];
    }
    return ans;
  }
};

void FST (vector<Modint> &a, bool invert) {
  for (int n = (int) a.size(), step = 1; step < n; step *= 2) {
    for (int i = 0; i < n; i += 2 * step) {
      for (int j = i; j < i + step; j++) {
        Modint &u = a[j], &v = a[j + step];
        tie(u, v) = make_pair(u + v, u - v);
      }
    }
  }

  if (invert) {
    Modint div = inv(Modint((int) a.size()));
    for (int i = 0; i < (int) a.size(); i++) {
      a[i] *= div;
    }
  }
}

vector<Modint> conv (vector<Modint> a, vector<Modint> b) {
  FST(a, 0);
  FST(b, 0);
  for (int i = 0; i < (int) a.size(); i++) {
    a[i] *= b[i];
  }
  FST(a, 1);
  return a;
}

int main () {
  ios::sync_with_stdio(false);

  p1e18[0] = 1;
  Modint bas = exp(Modint(10), 18);
  for (int i = 1; i < MAX_N; i++) {
    p1e18[i] = p1e18[i - 1] * bas;
  }

  int n;
  cin >> n;

  Graph g1 (n);
  int m1;
  cin >> m1;
  for (int i = 0; i < m1; i++) {
    int u, v;
    cin >> u >> v;

    g1.add_edge(u, v);
  }
  vector<Modint> a1 = g1.summary();

  Graph g2 (n);
  int m2;
  cin >> m2;
  for (int i = 0; i < m2; i++) {
    int u, v;
    cin >> u >> v;

    g2.add_edge(u, v);
  }
  vector<Modint> a2 = g2.summary();

  Graph g3 (n);
  int m3;
  cin >> m3;
  for (int i = 0; i < m3; i++) {
    int u, v;
    cin >> u >> v;

    g3.add_edge(u, v);
  }
  vector<Modint> a3 = g3.summary();

  vector<Modint> a1a2 = conv(a1, a2);
  vector<Modint> ans = conv(a1a2, a3);

  cout << ans[0] << endl;
}


Measured memory_bytes: 19828