#include <bits/stdc++.h>
using namespace std;

using ll = long long;

const int MAXN = 5005;
const int MAXK = 6;
const int MAXMASK = 1 << MAXK;
const int MOD = 998244353;

int n, k;
vector<int> g[MAXN];

int s[MAXK + 2];
int sz[MAXN];

// mx[mask] = największy numer operacji występujący w masce
int mx[MAXMASK];

// dp[v][first][mask]
//
// first:
// 1..k   -> najwcześniejsza operacja, która jest typu "keep subtree"
// k+1    -> nie ma jeszcze żadnej operacji "keep subtree"
//
int dp[MAXN][MAXK + 2][MAXMASK];

void dfs(int v, int par) {
    sz[v] = 1;

    // Na początku poddrzewo v zawiera tylko v.
    dp[v][k + 1][0] = 1;

    for (int u : g[v]) {
        if (u == par) continue;

        dfs(u, v);
        sz[v] += sz[u];

        static int tmp[MAXK + 2][MAXMASK];

        for (int i = 1; i <= k + 1; ++i)
            for (int mask = 0; mask < (1 << k); ++mask)
                tmp[i][mask] = 0;

        // Scalanie poddrzewa u z v.
        for (int first = 1; first <= k + 1; ++first) {
            for (int mask = 0; mask < (1 << k); ++mask) {

                if (!dp[v][first][mask]) continue;

                int available = (1 << k) - 1 - mask;

                // subset = operacje pochodzące z u
                for (int subset = available;; subset = (subset - 1) & available) {

                    // u nie ma własnego "keep subtree"
                    // albo jego pierwsze keep jest późniejsze niż first.
                    if (mx[subset] <= first) {
                        tmp[first][mask | subset] =
                            (tmp[first][mask | subset]
                             + 1LL * dp[v][first][mask]
                             * dp[u][k + 1][subset]) % MOD;
                    }

                    // v nie ma własnego "keep subtree"
                    // albo jego pierwsze keep jest późniejsze/nie wcześniejsze.
                    if (first != k + 1 && mx[mask] <= first) {
                        tmp[first][mask | subset] =
                            (tmp[first][mask | subset]
                             + 1LL * dp[v][k + 1][mask]
                             * dp[u][first][subset]) % MOD;
                    }

                    if (subset == 0) break;
                }
            }
        }

        for (int first = 1; first <= k + 1; ++first)
            for (int mask = 0; mask < (1 << k); ++mask)
                dp[v][first][mask] = tmp[first][mask];
    }

    // Krawędź (v, parent).
    // Dla korzenia jej nie ma.
    if (v == 1) return;

    static int tmp[MAXK + 2][MAXMASK];

    for (int first = 1; first <= k + 1; ++first)
        for (int mask = 0; mask < (1 << k); ++mask)
            tmp[first][mask] = dp[v][first][mask];

    for (int first = 1; first <= k + 1; ++first) {
        for (int mask = 0; mask < (1 << k); ++mask) {

            if (!dp[v][first][mask]) continue;

            // Wybieramy, że krawędź (v,parent)
            // odpowiada operacji j.
            for (int j = 1; j < first; ++j) {

                if (mask & (1 << (j - 1)))
                    continue;

                // Rozmiar aktualnego komponentu w poddrzewie v.
                // Wcześniejsze operacje < j, które są w tej masce,
                // musiały usunąć fragmenty.
                int currentSize = sz[v];

                for (int t = 1; t < j; ++t) {
                    if (mask & (1 << (t - 1))) {
                        currentSize -= s[t - 1] - s[t];
                    }
                }

                // 1) Operacja j = "keep subtree"
                //
                // Po odcięciu krawędzi zostawiamy stronę zawierającą v.
                // Jej rozmiar musi być s[j].
                if (currentSize == s[j]) {
                    tmp[j][mask | (1 << (j - 1))] =
                        (tmp[j][mask | (1 << (j - 1))]
                         + dp[v][first][mask]) % MOD;
                }

                // 2) Operacja j = "delete subtree"
                //
                // Usuwamy stronę zawierającą v.
                // Musi mieć rozmiar s[j-1] - s[j].
                //
                // Wszystkie operacje w tej części muszą być wcześniejsze
                // i żadna z nich nie może być typu "keep subtree".
                if (currentSize == s[j - 1] - s[j]
                    && mx[mask] < j) {

                    tmp[first][mask | (1 << (j - 1))] =
                        (tmp[first][mask | (1 << (j - 1))]
                         + dp[v][first][mask]) % MOD;
                }
            }
        }
    }

    for (int first = 1; first <= k + 1; ++first)
        for (int mask = 0; mask < (1 << k); ++mask)
            dp[v][first][mask] = tmp[first][mask];
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    cin >> n;

    for (int i = 0; i < n - 1; ++i) {
        int a, b;
        cin >> a >> b;
        g[a].push_back(b);
        g[b].push_back(a);
    }

    cin >> k;

    s[0] = n;
    for (int i = 1; i <= k; ++i) {
        cin >> s[i];
    }

    // Największy numer operacji w masce.
    for (int mask = 1; mask < (1 << k); ++mask) {
        for (int i = 1; i <= k; ++i) {
            if (mask & (1 << (i - 1))) {
                mx[mask] = max(mx[mask], i);
            }
        }
    }

    dfs(1, 0);

    int all = (1 << k) - 1;

    ll ans = 0;

    for (int first = 1; first <= k + 1; ++first) {
        ans += dp[1][first][all];
        ans %= MOD;
    }

    cout << ans << '\n';

    return 0;
}