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 C# (Mono 4.6.2.0) (judge verdict: Wrong Answer)

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using static System.Math;
using MethodImplAttribute = System.Runtime.CompilerServices.MethodImplAttribute;
using MethodImplOptions = System.Runtime.CompilerServices.MethodImplOptions;

public static class P
{
    static ModInt pow = new ModInt((long)1e18);
    //static ModInt pow = new ModInt(10);
    public static void Main()
    {
        #region READ_INPUT
        int n = int.Parse(Console.ReadLine());

        var m1 = int.Parse(Console.ReadLine());
        List<int>[] graph1 = Enumerable.Repeat(0, n).Select(_ => new List<int>()).ToArray();
        for (int i = 0; i < m1; i++)
        {
            var st = Console.ReadLine().Split().Select(x => int.Parse(x) - 1).ToArray();
            graph1[st[0]].Add(st[1]);
            graph1[st[1]].Add(st[0]);
        }

        var m2 = int.Parse(Console.ReadLine());
        List<int>[] graph2 = Enumerable.Repeat(0, n).Select(_ => new List<int>()).ToArray();
        for (int i = 0; i < m2; i++)
        {
            var st = Console.ReadLine().Split().Select(x => int.Parse(x) - 1).ToArray();
            graph2[st[0]].Add(st[1]);
            graph2[st[1]].Add(st[0]);
        }

        var m3 = int.Parse(Console.ReadLine());
        List<int>[] graph3 = Enumerable.Repeat(0, n).Select(_ => new List<int>()).ToArray();
        for (int i = 0; i < m3; i++)
        {
            var st = Console.ReadLine().Split().Select(x => int.Parse(x) - 1).ToArray();
            graph3[st[0]].Add(st[1]);
            graph3[st[1]].Add(st[0]);
        }
        #endregion   

        var greedyRes1 = GetGreedyRes(graph1);
        var greedyRes2 = GetGreedyRes(graph2);
        var greedyRes3 = GetGreedyRes(graph3);

        var res1 = GetHighDRes(new Tuple<ModInt, ModInt>(1, 0), greedyRes1);
        var res2 = GetHighDRes(res1, greedyRes2);
        var res3 = GetHighDRes(res2, greedyRes3);
        Console.WriteLine(res3.Item1);
    }
    static Tuple<ModInt, ModInt> GetHighDRes(Tuple<ModInt, ModInt> lowDRes, Tuple<bool[], bool[]> greedyRes)
    {
        bool[] freeMatch = greedyRes.Item1;
        bool[] strictedMatch = greedyRes.Item2;
        ModInt freeRes = 0;
        ModInt strictedRes = 0;
        ModInt curPowedFreeRes = lowDRes.Item1 * pow;
        ModInt curPowedStrictedRes = lowDRes.Item2 * pow;
        for (int i = 0; i < freeMatch.Length; i++)
        {
            if (freeMatch[i]) freeRes += curPowedFreeRes;
            else freeRes += curPowedStrictedRes;
            
            if (strictedMatch[i]) strictedRes += curPowedFreeRes;
            else strictedRes += curPowedStrictedRes;

            curPowedFreeRes *= pow;
            curPowedStrictedRes *= pow;
        }
        return new Tuple<ModInt, ModInt>(freeRes, strictedRes);
    }
    static Tuple<bool[], bool[]> GetGreedyRes(List<int>[] graph)
    {
        var freeRes = Enumerable.Repeat(true, graph.Length).ToArray();
        for (int i = freeRes.Length - 1; i >= 0; i--)
        {
            if (!freeRes[i]) continue;
            foreach (var adj in graph[i])
            {
                //if (i < adj) throw new Exception();
                freeRes[adj] = false;
            }
        }
        //↓ 上のやつとつながってて、だめですよ用に計算したもの
        var strictedRes = Enumerable.Repeat(true, graph.Length).ToArray();
        for (int i = freeRes.Length - 1; i >= 0; i--)
        {
            if (!strictedRes[i]) continue;
            if (freeRes[i]) //もし上がOKだったら、
            {
                strictedRes[i] = false; //当然だめ
                continue;
            }
            foreach (var adj in graph[i])
            {
                //if (i < adj) throw new Exception();
                strictedRes[adj] = false;
            }
        }

        return new Tuple<bool[], bool[]>(freeRes, strictedRes);
    }
}


struct ModInt
{
    public const int Mod = 998244353;
    const long POSITIVIZER = ((long)Mod) << 31;
    long Data;
    public ModInt(long data) { if ((Data = data % Mod) < 0) Data += Mod; }
    public static implicit operator long(ModInt modInt) => modInt.Data;
    public static implicit operator ModInt(long val) => new ModInt(val);
    public static ModInt operator +(ModInt a, int b) => new ModInt() { Data = (a.Data + b + POSITIVIZER) % Mod };
    public static ModInt operator +(ModInt a, long b) => new ModInt(a.Data + b);
    public static ModInt operator +(ModInt a, ModInt b) { long res = a.Data + b.Data; return new ModInt() { Data = res >= Mod ? res - Mod : res }; }
    public static ModInt operator -(ModInt a, int b) => new ModInt() { Data = (a.Data - b + POSITIVIZER) % Mod };
    public static ModInt operator -(ModInt a, long b) => new ModInt(a.Data - b);
    public static ModInt operator -(ModInt a, ModInt b) { long res = a.Data - b.Data; return new ModInt() { Data = res < 0 ? res + Mod : res }; }
    public static ModInt operator *(ModInt a, int b) => new ModInt(a.Data * b);
    public static ModInt operator *(ModInt a, long b) => a * new ModInt(b);
    public static ModInt operator *(ModInt a, ModInt b) => new ModInt() { Data = a.Data * b.Data % Mod };
    public static ModInt operator /(ModInt a, ModInt b) => new ModInt() { Data = a.Data * GetInverse(b) % Mod };
    public static bool operator ==(ModInt a, ModInt b) => a.Data == b.Data;
    public static bool operator !=(ModInt a, ModInt b) => a.Data != b.Data;
    public override string ToString() => Data.ToString();
    public override bool Equals(object obj) => (ModInt)obj == this;
    public override int GetHashCode() => (int)Data;
    static long GetInverse(long a)
    {
        long div, p = Mod, x1 = 1, y1 = 0, x2 = 0, y2 = 1;
        while (true)
        {
            if (p == 1) return x2 + Mod; div = a / p; x1 -= x2 * div; y1 -= y2 * div; a %= p;
            if (a == 1) return x1 + Mod; div = p / a; x2 -= x1 * div; y2 -= y1 * div; p %= a;
        }
    }
}