Problem:
Score : 900 points

Problem Statement

Given are simple undirected graphs X, Y, Z, with N vertices each and M_1, M_2, M_3 edges, respectively.
The vertices in X, Y, Z are respectively called x_1, x_2, \dots, x_N, y_1, y_2, \dots, y_N, z_1, z_2, \dots, z_N.
The edges in X, Y, Z are respectively (x_{a_i}, x_{b_i}), (y_{c_i}, y_{d_i}), (z_{e_i}, z_{f_i}).

Based on X, Y, Z, we will build another undirected graph W with N^3 vertices.
There are N^3 ways to choose a vertex from each of the graphs X, Y, Z. Each of these choices corresponds to the vertices in W one-to-one. Let (x_i, y_j, z_k) denote the vertex in W corresponding to the choice of x_i, y_j, z_k.

We will span edges in W as follows:

For each edge (x_u, x_v) in X and each w, l, span an edge between (x_u, y_w, z_l) and (x_v, y_w, z_l).

For each edge (y_u, y_v) in Y and each w, l, span an edge between (x_w, y_u, z_l) and (x_w, y_v, z_l).

For each edge (z_u, z_v) in Z and each w, l, span an edge between (x_w, y_l, z_u) and (x_w, y_l, z_v).

Then, let the weight of the vertex (x_i, y_j, z_k) in W be 1,000,000,000,000,000,000^{(i +j + k)} = 10^{18(i + j + k)}. Find the maximum possible total weight of the vertices in an independent set in W, and print that total weight modulo 998,244,353.

Constraints

2 \leq N \leq 100,000

1 \leq M_1, M_2, M_3 \leq 100,000

1 \leq a_i, b_i, c_i, d_i, e_i, f_i \leq N

X, Y, and Z are simple, that is, they have no self-loops and no multiple edges.

Input

Input is given from Standard Input in the following format:

N
M_1
a_1 b_1
a_2 b_2
\vdots
a_{M_1} b_{M_1}
M_2
c_1 d_1
c_2 d_2
\vdots
c_{M_2} d_{M_2}
M_3
e_1 f_1
e_2 f_2
\vdots
e_{M_3} f_{M_3}

Output

Print the maximum possible total weight of an independent set in W, modulo 998,244,353.

Sample Input 1

2
1
1 2
1
1 2
1
1 2

Sample Output 1

46494701

The maximum possible total weight of an independent set is that of the set (x_2, y_1, z_1), (x_1, y_2, z_1), (x_1, y_1, z_2), (x_2, y_2, z_2). The output should be (3 \times 10^{72} + 10^{108}) modulo 998,244,353, which is 46,494,701.

Sample Input 2

3
3
1 3
1 2
3 2
2
2 1
2 3
1
2 1

Sample Output 2

883188316

Sample Input 3

100000
1
1 2
1
99999 100000
1
1 100000

Sample Output 3

318525248

Solution in Rust (1.15.1) (judge verdict: Wrong Answer)

use std::io::{self, BufRead};
use std::collections::{HashSet, BinaryHeap};
use std::cmp::Ordering;

const M: i64 = 998244353;
const ten18: i64 = 1_000_000_000_000_000_000 % M;

#[derive(PartialEq, Eq, Debug, Copy, Clone, Default, Hash)]
struct Vertex(usize, usize, usize, usize);

impl PartialOrd for Vertex {
    #[inline]
    fn partial_cmp(&self, other: &Vertex) -> Option<Ordering> {
        self.0.partial_cmp(&other.0)
    }

    #[inline]
    fn lt(&self, other: &Self) -> bool {
        self.0 < other.0
    }
    #[inline]
    fn le(&self, other: &Self) -> bool {
        self.0 <= other.0
    }
    #[inline]
    fn gt(&self, other: &Self) -> bool {
        self.0 > other.0
    }
    #[inline]
    fn ge(&self, other: &Self) -> bool {
        self.0 >= other.0
    }
}

impl Ord for Vertex {
    #[inline]
    fn cmp(&self, other: &Vertex) -> Ordering {
        self.0.cmp(&other.0)
    }
}

fn find_adjacent_vertices(edges: &Vec<Vec<HashSet<usize>>>, x: usize, y: usize, z: usize) -> Vec<(usize, usize, usize)> {
  let mut result = Vec::new();
  for i in &edges[0][x] {
    result.push((*i, y, z));
  }
  for i in &edges[1][y] {
    result.push((x, *i, z));
  }
  for i in &edges[2][z] {
    result.push((x, y, *i));
  }
  result
}

fn bfs(edges: &Vec<Vec<HashSet<usize>>>, passed: &mut HashSet<(usize, usize, usize)>, checked: &mut HashSet<(usize, usize, usize)>, forbidden: &mut HashSet<(usize, usize, usize)>, queue: &mut BinaryHeap<Vertex>) {
  while let Some(Vertex(p, x, y, z)) = queue.pop() {
    if passed.contains(&(x, y, z)) {
      continue;
    }
    passed.insert((x, y, z));
    if !forbidden.contains(&(x, y, z)) {
      checked.insert((x, y, z));
      for (x1, y1, z1) in find_adjacent_vertices(edges, x, y, z) {
        if !passed.contains(&(x1, y1, z1)) {
          forbidden.insert((x1, y1, z1));
        }
      }
    }
    for (x1, y1, z1) in find_adjacent_vertices(edges, x, y, z) {
      if !checked.contains(&(x1, y1, z1)) {
        queue.push(Vertex(x1+y1+z1, x1, y1, z1));
      }
    }
  }
}

fn main() {
  let stdin = io::stdin();
  let mut lines = stdin.lock().lines();
  let line = lines.next().unwrap().unwrap();
  let n: usize = line.parse().unwrap();
  let mut edges: Vec<Vec<HashSet<usize>>> = vec![vec![HashSet::new(); n]; 3];
  for i in 0..3 {
    let line = lines.next().unwrap().unwrap();
    let m: usize = line.parse().unwrap();
    for _ in 0..m {
      let line = lines.next().unwrap().unwrap();
      let vs: Vec<usize> = line.split(' ').map(|x| x.parse().unwrap()).map(|v: usize| v - 1).collect();
      let j = vs[0];
      let k = vs[1];
      edges[i][j].insert(k);
      edges[i][k].insert(j);
    }
  }

  let mut checked: HashSet<(usize, usize, usize)> = HashSet::new();
  let mut forbidden: HashSet<(usize, usize, usize)> = HashSet::new();
  let mut passed: HashSet<(usize, usize, usize)> = HashSet::new();
  let mut queue: BinaryHeap<Vertex> = BinaryHeap::new();
  queue.push(Vertex(3*n-3, n-1, n-1, n-1));
  bfs(&edges, &mut passed, &mut checked, &mut forbidden, &mut queue);

  let mut memo: Vec<i64> = vec![0; 3*n+1];
  memo[0] = (ten18 * ten18 % M) * ten18 % M;
  for i in 1..(3*n+1) {
    memo[i] = memo[i-1] * ten18 % M;
  }
  let mut ans: i64 = 0;
  for (x, y, z) in checked {
    ans = (ans + memo[x + y + z]) % M;
  }

  println!("{}", ans);
}