#include "bits/stdc++.h"

using namespace std;

//int N,M,K,L,R,H,W;
long long int N,M,K,L,R,H,W;

constexpr long long int MOD=1000000007;
//constexpr  int MOD=1000000007;
//constexpr int MOD=998244353;
//constexpr long long int MOD=998244353;

constexpr long double EPS=1e-8;

//
// Writer: kurita
// states: AC
// O(N log(N))
//

#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<map>
#include<cstdio>
using namespace std;
typedef pair<int, int> pii;
typedef vector<vector<int> > Graph;
map<vector<int>, int> tree_hash;

vector<Graph> ConectedComponent(Graph &f) {
  int n = f.size(), pos = 0;
  vector<bool> used(n, false);
  vector<Graph> res;
  queue<int> que;
  while(pos < n){
    vector<int> used_vertex;
    int size = 0;
    que.push(pos);
    used[pos] = true;
    while(not que.empty()){
      size++;
      int v = que.front();
      used_vertex.push_back(v);
      que.pop();
      for (int i = 0; i < f[v].size(); i++) {
        if(used[f[v][i]] == true)continue;
        que.push(f[v][i]);
        used[f[v][i]] = true;
      }
    }
    sort(used_vertex.begin(), used_vertex.end());
    Graph g(used_vertex.size());
    for (int i = 0; i < used_vertex.size(); i++) {
      for (int j = 0; j < f[used_vertex[i]].size(); j++) {
        g[i].push_back(lower_bound(used_vertex.begin(), used_vertex.end(), f[used_vertex[i]][j]) -
                       used_vertex.begin());
      }
    }
    res.push_back(g);
    while(pos < n and used[pos])pos++;
  }
  return res;
}

vector<int> BFS(const Graph &g, vector<int> &dist, int v){
  int n = g.size();
  queue<pii> que;
  vector<int> parent(n);
  for (int i = 0; i < n; i++) parent[i] = i;
  que.push(pii(v, 0));
  dist[v] = 0;
  while(not que.empty()){
    int v = que.front().first;
    int d = que.front().second;
    que.pop();
    for (int i = 0; i < g[v].size(); i++) {
      if(dist[g[v][i]] >= 0)continue;
      dist[g[v][i]] = d + 1;
      parent[g[v][i]] = v;
      que.push(pii(g[v][i], d + 1));
    }
  }
  return parent;
}

inline vector<int> CenterTree(const Graph &g, int v = 0){
  int n = g.size();
  vector<int> dist(n, -1);
  BFS(g, dist, v);
  int u, maxi = -1;
  for (int i = 0; i < n; i++) {
    if(dist[i] > maxi){
      u = i, maxi = dist[i];
    }
  }
  dist = vector<int>(n, -1);
  vector<int> parent = BFS(g, dist, u);
  int diam = 0;
  for (int i = 0; i < n; i++) {
    if(dist[i] > diam) diam = dist[i], v = i;
  }
  
  for (int i = 0; i < diam/2; i++) v = parent[v];
  
  vector<int> res;
  res.push_back(v);
  if(diam%2 != 0)res.push_back(parent[v]);
  return res;
}

int AHUHash(const Graph &t, int v, int parent = -1){
  if(t[v].size() == 1 and parent != -1)return 0;
  vector<int> res;
  for (int i = 0; i < t[v].size(); i++) {
    if(t[v][i] == parent)continue;
    res.emplace_back(AHUHash(t, t[v][i], v));
  }
  sort(res.begin(), res.end());
  if(tree_hash.count(res) == 0){
    tree_hash[res] = 0;
    tree_hash[res] = tree_hash.size();
  }
  return tree_hash[res];
}


class UnionFind {
	vector<int>parent;
	vector<int>rank;
public:
	UnionFind(int num) {
		num++;
		parent.resize(num);
		rank.resize(num);
		for (int i = 0; i < num; i++) {
			parent[i] = i;
			rank[i] = 0;
		}
	}
	int Find(int node) {
		if (parent[node] == node)return node;
		else return parent[node] = Find(parent[node]);
	}
	void Unite(int u, int v) {
		u = Find(u);
		v = Find(v);
		if (u == v)return;
		if (rank[u] < rank[v])parent[u] = v;
		else {
			parent[v] = u;
			if (rank[u] == rank[v])rank[u]++;
		}
	}
	bool Check_Same(int u, int v) {
		return Find(u) == Find(v);
	}
};


int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	cin>>N>>M;
	Graph forest(N);
	for(int i=0;i<M;i++){
		cin>>L>>R;
		L--;
		R--;
		forest[L].push_back(R);
		forest[R].push_back(L);
	}
	cin>>K;
	Graph tree(K);
	for(int i=1;i<K;i++){
		cin>>L>>R;
		L--;
		R--;
		tree[L].push_back(R);
		tree[R].push_back(L);
	}
	UnionFind uf(N);
	for(int i=0;i<N;i++){
		for(auto j:forest[i]){
			uf.Unite(i,j);
		}
	}
	vector<vector<int>>parent(N);
	for(int i=0;i<N;i++){
		parent[uf.Find(i)].push_back(i);
	}
	int ans=0;
	auto Deforest=ConectedComponent(forest);
	auto center_tree=CenterTree(tree);
	vector<int>th;
	for(auto i:center_tree){
		th.push_back(AHUHash(tree,i));
	}
	for(auto i:Deforest){
		auto cf=CenterTree(i);
		int add=0;
		for(auto j:th){
			for(auto k:cf){
				if(j==AHUHash(i,k))add=1;
			}
		}
		ans+=add;
	}
	cout<<ans<<endl;
	return 0;
}


Measured memory_bytes: 101572