#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;
}