#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
#define int ll

#define REP(i,n) for(int i=0;i<n;++i)
#define ALL(name) name.begin(),name.end()
#define SORT(name) sort(name.begin(), name.end())
#define ZERO(p) memset(p, 0, sizeof(p))
#define MINUS(p) memset(p, -1, sizeof(p))
#if 0
#  define DBG(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#  define DBG(fmt, ...)
#endif

const ll LLINF = (1LL<<60);
const int INF = (1LL<<30);
const double DINF = std::numeric_limits<double>::infinity();
const int MOD = 1000000007;
#define MAX_N 51
#define MAX_M 21

#define SUBMIT

// n 頂点 m 辺の無向連結グラフを作成し edges に辺情報を格納する
// 頂点数は [n_min, n_max] の間でランダム
// 辺数は [m_min, m_max] の間でランダム。
//   ただしグラフが連結になれない or 自己辺や二重辺が必要になる辺数にはならない
// 辺のコストは [cost_min, cost_max] の間でランダム
// tuple は <0> from, <1> to, <2> cost の順番 (from < to && from != to)
// ノード id は [0, n)
// 作成に成功した場合は 頂点数 first と辺数 second を pair にして返す
// 作成に失敗した場合は {-1, -1} が返る
// n <= 1000, m <= 499500 程度まで作成可能
// O(n^2)
pair<ll, ll> MakeConnectedUndirGraph(mt19937& mt, vector< tuple<ll, ll, ll> >& edges,
        const ll n_min, const ll n_max, ll m_min, ll m_max,
        const ll cost_min, const ll cost_max) {
    assert(n_min > 0);
    assert(m_min >= n_min - 1);
    edges.clear();

    // ノード数と辺数の決定
    uniform_int_distribution<> dist_n(n_min, n_max);
    ll n = dist_n(mt);
    if(n == 1) { return make_pair(n, 0); }

    m_min = max(n - 1, m_min);
    m_max = min(n * (n - 1) / 2, m_max);
    uniform_int_distribution<> dist_m(m_min, m_max);
    ll m = dist_m(mt);

    uniform_int_distribution<> dist_cost(cost_min, cost_max);

    vector< vector<bool> > graph(n, vector<bool>(n, false) );   // i と j の辺があるなら true
    vector< pair<ll, ll> > pattern;                             // 辺の張り方全パターン

    // まず全ての頂点を連結にする
    vector<ll> connected;
    ll node = (mt() % (n - 1)) + 1;
    ll cost = dist_cost(mt);

    connected.push_back(0);
    connected.push_back(node);
    edges.push_back(make_tuple(0, node, cost));
    graph[0][node] = true;

    for(ll i = 1; i < n; ++i) {
        if(i == node) { continue; }
        // 連結済み頂点の中からひとつをランダムに選びそれに接続する
        ll to = connected[mt() % connected.size()];
        cost = dist_cost(mt);
        connected.push_back(i);
        edges.push_back(make_tuple(min(i, to), max(i, to), cost));
        graph[min(i, to)][max(i, to)] = true;
    }

    for(ll i = 0; i < n; ++i) {
        for(ll j = i + 1; j < n; ++j) {
            if(!graph[i][j]) { pattern.push_back(make_pair(i, j)); }
        }
    }
    shuffle(pattern.begin(), pattern.end(), mt);

    // まだ辺が引かれていない点どうしに辺を張る
    for(ll i = 0; i < (m - (n - 1)); ++i) {
        cost = dist_cost(mt);
        edges.push_back(make_tuple(pattern[i].first, pattern[i].second, cost));
    }
    assert(edges.size() == static_cast<size_t>(m));

    return make_pair(n, m);
}

// n 頂点の木を作成します
// 頂点数は [n_min, n_max] の間でランダム
// 辺のコストは [cost_min, cost_max] の間でランダム
// tuple は <0> from, <1> to, <2> cost の順番 (from < to && from != to)
// 作成に成功した場合は頂点数が、失敗した場合は -1 が返る
// n <= 1000, m <= 499500 程度まで作成可能
// O(n^2)
ll MakeTree(mt19937& mt, vector< tuple<ll, ll, ll> >& edges,
        const ll n_min, const ll n_max, const ll cost_min, const ll cost_max) {
    assert(n_min > 0);

    uniform_int_distribution<> dist_n(n_min, n_max);
    ll n = dist_n(mt);
    pair<ll, ll> ret = MakeConnectedUndirGraph(mt, edges, n, n, n-1, n-1, cost_min, cost_max);

    return ret.first;
}

template <typename T, typename U>
class Dijkstra {
    private:
        struct Edge {
            T to;   // 有向辺の行先頂点
            U cost;  // 辺の重み
        };
        typedef pair<U, T> P;       // first: 最短距離 second: 頂点 id
    public:
        // コンストラクタ
        // v … 頂点数, inf: …「無限大」とする値
        Dijkstra() {}
        Dijkstra(T v, U inf) { Init(v, inf); }
        void Init(T v, U inf) {
            m_V = v;
            m_Inf = inf;
            m_G.assign(m_V, vector<Edge>());
        }
        // 有向辺の追加。負のコストは未対応
        void AddDirEdge(T from, T to, U cost) { m_G[from].push_back({to, cost}); }
        // 無向辺の追加。負のコストは未対応
        void AddUndirEdge(T from, T to, U cost) {
            AddDirEdge(from, to, cost);
            AddDirEdge(to, from, cost);
        }
        // 始点 s から各頂点への最短経路の導出 O(E log V)
        // Calc を連続で行うことはできない。その場合は m_Dist と m_Prev の再初期化が必要
        void Calc(T s) {
            m_Dist.assign(m_V, m_Inf);
            m_PrevP.assign(m_V, -1);
            // 最短距離が短い順で cand を取り出す
            // 頂点 P.second まで P.first のコストで来れたことを情報として入れておく
            priority_queue<P, vector<P>, greater<P> > cand;
            m_Dist[s] = 0;  // 始点のコストは 0
            cand.push(P(0, s));
            while(!cand.empty()) {
                P p = cand.top(); cand.pop();     // cand のトップを取り出す
                T v = p.second;
                // 頂点 v まで最短経路が、 cand から取り出したものより既に小さいなら何もしない
                if(m_Dist[v] < p.first){ continue; }
                // 現在見ている頂点から延びている辺を全て見る
                for(Edge e : m_G[v]) {
                    if(m_Dist[e.to] > m_Dist[v] + e.cost) {
                        // 現在の最短経路より短くなるなら更新
                        m_Dist[e.to] = m_Dist[v] + e.cost;
                        m_PrevP[e.to] = v;
                        cand.push(P(m_Dist[e.to], e.to));
                    }
                }
            }
        }
        // 始点 s から頂点 t への最短距離を返す O(1)
        // 前処理として Calc(s) が必要
        U GetDist(T t) { return m_Dist[t]; }
        // 始点 s から頂点 t までの経路を vector に入れて返す (s と t 含む)
        // O(V') … V' は最短経路の頂点数
        // 前処理として Calc(s) が必要
        vector<T> GetPath(T t) {
            vector<T> path;
            for(; t != -1; t = m_PrevP[t]) { path.push_back(t); }  // t が s になるまで prev_p[t] を辿っていく
            // このままだと t->s の順になっているので逆順にする
            reverse(path.begin(), path.end());
            return path;
        }
    private:
        T m_V;                // 頂点の数
        U m_Inf;              // 無限の代わりとして扱う値
        vector< vector<Edge> > m_G; // 頂点 i から延びている辺の vector(隣接リスト)
        vector<U> m_Dist;           // 各頂点への最短コスト。つまり答え
        vector<T> m_PrevP;          // 最短経路の各頂点を保存(経路復元で利用)
};

// n を size 桁の二進数文字列表現 string にして返す
string Binf(int n, int size) {
    assert(size <= sizeof(int) * 8);
    string res = "";
    REP(i, size) {
        if((n >> i) & 1) { res += '1'; }
        else { res += '0'; }
    }
    reverse(res.begin(), res.end());
    return res;
}

// n を二進数文字列表現 string にして返す
string Binf2(int n) {
    // 最上位ビットを探す
    ll top = 0;
    for(int i = 0; i < sizeof(int) * 8; ++i) {
        if((n >> i) & 1) { top = i; }
    }
    return Binf(n, top + 1);
}

int N, M;
vector< pair<ll, ll> > AB;
vector< pair<ll, ll> > UV;

ll dp[MAX_N][(1LL << MAX_M) + 1];

vector< pair<int, int> > id_to_edge;    // id i の辺の両端を返す ( first < second )
int edge_to_id[MAX_N][MAX_N];           // i, j の辺の id を返す。ない場合は -1

vector<int> m_cond;                     // 条件 i [0, M) を満たすために必要な黒くすべき辺のパターン（ビット）
vector<int> e_cond;                     // 辺 i [0, N-1) を黒くしたときに満たされる条件のパターン（ビット）

Dijkstra<int, ll> dk;

// i 番目の辺を見ていて、現状満たされている条件が pat のときの
// 条件を満たしている経路のパターン数
ll dfs(int i, int pat) {
    if(i >= N - 1) {
        int ans = (1LL << M) - 1;
        if(pat == ans) { return 1; }
        return 0;
    }

    ll& ret = dp[i][pat];
    if(~ret) { return ret; }
    ret = 0;

    // この辺を黒くした場合
    ret = dfs(i + 1, pat | e_cond[i]);

    // この辺を黒くしない場合
    ret += dfs(i + 1, pat);

    return ret;
}

ll solve() {
    REP(i, N - 1) {
        int a = AB[i].first;
        int b = AB[i].second;
        dk.AddUndirEdge(a, b, 1);

        if(a > b) { swap(a, b); }
        id_to_edge.push_back(make_pair(a, b));
        edge_to_id[a][b] = i;
        edge_to_id[b][a] = i;
    }
    REP(i, M) {
        int u = UV[i].first;
        int v = UV[i].second;
        // u - v の経路を取得
        dk.Calc(u);
        auto path = dk.GetPath(v);
        ll bit_pat = 0;
        for(int j = 0; j < path.size() - 1; ++j) {
            // 辺 id の取得
            int e_id = edge_to_id[path[j]][path[j+1]];
            assert(e_id >= 0);
            bit_pat |= (1LL << e_id);
        }
        m_cond.push_back(bit_pat);

        DBG("m_cond[%lld]: %s\n", i, Binf(bit_pat, 8).c_str());
    }

    // e_cond の作成
    e_cond.assign(N, 0);
    for(int e_id = 0; e_id < N - 1; ++e_id) {
        for(int i = 0; i < M; ++i) {
            if((m_cond[i] >> e_id) & 1) {
                e_cond[e_id] |= (1LL << i);
            }
        }
        DBG("e_cond[%lld]: %s\n", e_id, Binf(e_cond[e_id], 8).c_str());
    }

    MINUS(dp);
    return dfs(0, 0);
}

ll brute_force() {
    ll ret = 0;
    // 辺のパターン
    for(int pat = 0; pat < (1LL << (N-1)); pat++) {
        int cnt = 0;
        REP(i, M) {
            int u = UV[i].first;
            int v = UV[i].second;
            // u - v の経路を取得
            dk.Calc(u);
            auto path = dk.GetPath(v);
            bool isOk = false;
            for(int j = 0; j < path.size() - 1; ++j) {
                // 辺 id の取得
                int e_id = edge_to_id[path[j]][path[j+1]];   // solve を先に実行しておくこと
                assert(e_id >= 0);
                if((pat >> e_id) & 1) {
                    isOk = true;
                    break;
                }
            }
            if(isOk) { cnt++; }
            else { break; }
        }
        if(cnt == M) { ret++; }
    }
    return ret;
}
signed main() {
    cin.tie(0); cout.tie(0);
    ios::sync_with_stdio(false);

#if defined(SUBMIT)
    cin >> N;
    dk.Init(N, LLINF);
    MINUS(edge_to_id);
    REP(i, N - 1) {
        int a, b;
        cin >> a >> b;
        a--;
        b--;
        AB.push_back(make_pair(a, b));
    }

    cin >> M;
    REP(i, M) {
        int u, v;
        cin >> u >> v;
        u--;
        v--;
        UV.push_back(make_pair(u, v));
    }

    ll cand = solve();
    //ll ans = brute_force();
    //printf("%lld\n", ans);
    printf("%lld\n", cand);
#else
#endif

    return 0;
}


Measured memory_bytes: 835840