#include <bits/stdc++.h>
using namespace std;
const int N = 1020 , M = 15;
const int Mod = 1000000007;
int n,m,t1,t2,Head1[N],Head2[N];
int g[1<<M],p[1<<M],ans;
map < int , vector<int> > List;
map < int , int > f[N];
struct edge { int ver,next; } e1[N*2],e2[N*2];
inline void insert(int x,int y,int id)
{
    if ( id == 1 )
        e1[++t1] = (edge){y,Head1[x]} , Head1[x] = t1,
        e1[++t1] = (edge){x,Head1[y]} , Head1[y] = t1;
    if ( id == 2 )
        e2[++t2] = (edge){y,Head2[x]} , Head2[x] = t2,
        e2[++t2] = (edge){x,Head2[y]} , Head2[y] = t2;
}
inline int read(void)
{
    int x = 0 , w = 0; char ch = ' ';
    while ( !isdigit(ch) ) w |= ch=='-' , ch = getchar();
    while ( isdigit(ch) ) x = x*10 + ch-48 , ch = getchar();
    return w ? -x : x;
}
inline void input(void)
{
    n = read();
    for (int i=1;i<n;i++)
        insert( read() , read() , 1 );
    m = read();
    for (int i=1;i<m;i++)
        insert( read() , read() , 2 );
}
inline int lenth(int x) { return 32 - __builtin_clz(x); }
inline void connect(int &x,int y) { x = x << lenth(y) | y; }
inline int Ergodic(int x,int fa)
{
    int S = 1;
    vector < int > cur;
    for (int i=Head2[x];i;i=e2[i].next)
    {
        int y = e2[i].ver;
        if ( y == fa ) continue;
        cur.push_back( Ergodic( y , x ) );
    }
    sort( cur.begin() , cur.end() );
    vector < int > :: iterator it;
    for (it=cur.begin();it!=cur.end();it++)
        connect( S , *it );
    S <<= 1;
    if ( !List.count( S ) ) List[S] = cur;
    return S;
}
inline void dp(int x,int fa)
{
    vector < int > ch;
    for (int i=Head1[x];i;i=e1[i].next)
    {
        int y = e1[i].ver;
        if ( y == fa ) continue;
        ch.push_back( y ) , dp( y , x );
    }
    map < int , vector< int > > :: iterator it;
    for (it=List.begin();it!=List.end();it++)
    {
        vector < int > cur = it -> second;
        int S = it -> first , len = cur.size();
        memset( g , 0 , sizeof g );
        g[0] = 1;
        for (int i=0;i<ch.size();i++)
        {
            memcpy( p , g , sizeof g );
            for (int j=0;j<len;j++)
            {
                int val = f[ch[i]][cur[j]];
                if ( val == 0 ) continue;
                for (int k=(1<<len)-1;k>=0;k--)
                    if ( g[k] && !( k >> j & 1 ) && ( j == 0 || cur[j] != cur[j-1] || ( k >> (j-1) & 1 ) ) )
                        p[k|(1<<j)] = ( p[k|(1<<j)] + 1LL * g[k] * val % Mod ) % Mod;
            }
            memcpy( g , p , sizeof p );
        }
        if ( g[(1<<len)-1] )
        {
            f[x][S] = g[(1<<len)-1];
            if ( lenth(S) == (m<<1) )
                ans = ( ans + f[x][S] ) % Mod;
        }
    }
}
int main(void)
{
    freopen("tree.in","r",stdin);
    freopen("tree.out","w",stdout);
    input();
    for (int i=1;i<=m;i++)
        Ergodic( i , 0 );
    dp( 1 , 0 );
    printf("%d\n",ans);
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
const int N = 1020 , M = 15;
const int Mod = 1000000007;
int n,m,t1,t2,Head1[N],Head2[N];
int g[1<<M],p[1<<M],ans;
map < int , vector<int> > List;
map < int , int > f[N];
struct edge { int ver,next; } e1[N*2],e2[N*2];
inline void insert(int x,int y,int id)
{
    if ( id == 1 )
        e1[++t1] = (edge){y,Head1[x]} , Head1[x] = t1,
        e1[++t1] = (edge){x,Head1[y]} , Head1[y] = t1;
    if ( id == 2 )
        e2[++t2] = (edge){y,Head2[x]} , Head2[x] = t2,
        e2[++t2] = (edge){x,Head2[y]} , Head2[y] = t2;
}
inline int read(void)
{
    int x = 0 , w = 0; char ch = ' ';
    while ( !isdigit(ch) ) w |= ch=='-' , ch = getchar();
    while ( isdigit(ch) ) x = x*10 + ch-48 , ch = getchar();
    return w ? -x : x;
}
inline void input(void)
{
    n = read();
    for (int i=1;i<n;i++)
        insert( read() , read() , 1 );
    m = read();
    for (int i=1;i<m;i++)
        insert( read() , read() , 2 );
}
inline int lenth(int x) { return 32 - __builtin_clz(x); }
inline void connect(int &x,int y) { x = x << lenth(y) | y; }
inline int Ergodic(int x,int fa)
{
    int S = 1; vector < int > cur;
    for (int i=Head2[x];i;i=e2[i].next)
    {
        int y = e2[i].ver;
        if ( y == fa ) continue;
        cur.push_back( Ergodic( y , x ) );
    }
    vector < int > :: iterator it;
    for (it=cur.begin();it!=cur.end();it++)
        connect( S , *it );
    S <<= 1;
    if ( !List.count( S ) ) List[S] = cur;
    return S;
}
inline void dp(int x,int fa)
{
    vector < int > ch;
    for (int i=Head1[x];i;i=e1[i].next)
    {
        int y = e1[i].ver;
        if ( y == fa ) continue;
        ch.push_back( y ) , dp( y , x );
    }
    map < int , vector< int > > :: iterator it;
    for (it=List.begin();it!=List.end();it++)
    {
        vector < int > cur = it -> second;
        int S = it -> first , len = cur.size();
        memset( g , 0 , sizeof g );
        g[0] = 1;
        for (int i=0;i<ch.size();i++)
        {
            memcpy( p , g , sizeof g );
            for (int j=0;j<len;j++)
            {
                int val = f[ch[i]][cur[j]];
                if ( val == 0 ) continue;
                for (int k=(1<<len)-1;k>=0;k--)
                    if ( g[k] && !( k >> j & 1 ) && !( j && cur[j] == cur[j-1] && !( k >> (j-1) & 1 ) ) )
                        p[k|(1<<j)] = ( p[k|(1<<j)] + 1LL * g[k] * val % Mod ) % Mod;
            }
            memcpy( g , p , sizeof p );
        }
        if ( g[(1<<len)-1] )
        {
            f[x][S] = g[(1<<len)-1];
            if ( lenth(S) == (m<<1) ) ans = ( ans + f[x][S] ) % Mod;
        }
    }
}
int main(void)
{
    input();
    for (int i=1;i<=m;i++)
        Ergodic( i , 0 );
    dp( 1 , 0 );
    printf("%d\n",ans);
    return 0;
}


/// by ztx
/// blog.csdn.net/hzoi_ztx
/// learnt from myy  (matthew99:http://codeforces.com/contest/762/submission/24128833)

#define Rep(i,l,r) for(i=(l);i<=(r);i++)
#define rep(i,l,r) for(i=(l);i< (r);i++)
#define r(x)   read(x)
typedef long long ll ;
int CH , NEG ;
template <typename TP>inline void read(TP& ret) {
    ret = NEG = 0 ; while (CH=getchar() , CH<'!') ;
    if (CH == '-') NEG = true , CH = getchar() ;
    while (ret = ret*10+CH-'0' , CH=getchar() , CH>'!') ;
    if (NEG) ret = -ret ;
}
using namespace std;
#define  kN   1000LL
#define  kM   12LL
#define  pb   push_back
#define  kMod 1000000007LL

int n, m, ANS;
int now[(1<<kM)+5], nxt[(1<<kM)+5];
vector<int> G[kN+5], g[kM+5];
map<int,vector<int> > STA;
map<int,int> ans[kN+5];

inline int blen(int x) { return 32 - __builtin_clz(x); } // __builtin_clz()   count leading zeros
inline int combine(int x, int y) { return x << blen(y) | y; }

inline void P(int x) {
    for (int i = 30; ~i; i -- ) { printf("%d",int(bool(x&(1<<i)))); } puts("");
}

int dfs0(int u,int fa = 0) {
    int h = 1;
    vector<int> H;
    for (auto v : g[u]) if (v != fa) H.pb(dfs0(v,u));
    sort(H.begin(), H.end());
    // minimum representation of tree
    for (auto s : H) h = combine(h,s);
    h <<= 1;
//printf("h[%d] = ",u);
//P(h);
    if (!STA.count(h)) STA[h] = H;
    return h;
}

void dfs(int u,int fa = 0) {
    vector<int> chd;
    for (auto v : G[u]) if (v != fa) chd.pb(v), dfs(v,u);
    for (const auto &sta : STA) {
        auto &H = sta.second;
        int h = sta.first, N = H.size();
        memset(now, 0, sizeof(int)*(1<<N));
        now[0] = 1;
        for (auto ch : chd) {
            memcpy(nxt, now, sizeof(int)*(1<<N));
            for (int i = 0; i < N; i ++ ) {
                int num = ans[ch][H[i]];
                if (!num) continue;
                for (int j = (1<<N)-1; j >= 0; j -- )
                    if (now[j] && !(j>>i & 1) && !(i && H[i]==H[i-1] && !(j>>(i-1) & 1)))
                        (nxt[j|(1<<i)] += (ll)now[j]*num%kMod) %= kMod;
            }
            memcpy(now, nxt, sizeof(int)*(1<<N));
        }
        if (now[(1 << N) - 1]) {
            ans[u][h] = now[(1 << N) - 1];
            if (blen(h) == (m<<1)) (ANS += now[(1<<N)-1]) %= kMod;
        }
    }
}

int main() {
    int i, u, v;
    r(n);
    rep (i,1,n)
        r(u), r(v), G[u].pb(v), G[v].pb(u);
    r(m);
    rep (i,1,m)
        r(u), r(v), g[u].pb(v), g[v].pb(u);
    Rep (i,1,m) dfs0(i);
    dfs(1);
    (ANS += kMod) %= kMod;
    printf("%d\n", ANS);
    return 0;
}


#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#include <cstring>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <list>
#include <cassert>
#include <ctime>
#include <climits>
using namespace std;

#define PB push_back
#define MP make_pair
#define SZ(v) ((int)(v).size())
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n) FOR(i,0,n)
#define FORE(i,a,b) for(int i=(a);i<=(b);++i)
#define REPE(i,n) FORE(i,0,n)
#define FORSZ(i,a,v) FOR(i,a,SZ(v))
#define REPSZ(i,v) REP(i,SZ(v))
typedef long long ll;
typedef unsigned long long ull;
ll gcd(ll a,ll b) { return b==0?a:gcd(b,a%b); }

const int MAXSN=1000;
const int MAXSM=MAXSN-1;
const int MAXTN=12;
const int MAXTM=MAXTN-1;
const int MOD=1000000007;

int sn;
int shead[MAXSN],snxt[2*MAXSM],sto[2*MAXSM];
int tn;
int thead[MAXTN],tnxt[2*MAXTM],tto[2*MAXTM];

int tsz[2*MAXTM];
int calctsz(int x) {
	if(tsz[x]!=0) return tsz[x]; else tsz[x]=1;
	int at=tto[x];
	for(int y=thead[at];y!=-1;y=tnxt[y]) if((y^1)!=x) tsz[x]+=calctsz(y);
	return tsz[x];
}

int memst[MAXSN+2*MAXSM][MAXTN+2*MAXTM];
int memtt[MAXTN+2*MAXTM][MAXTN+2*MAXTM];
int z[MAXTN],nz;
int dp[1<<MAXTN];
int calcst(int av,int pax,int bv,int pbx) {
	int aid=pax==-1?av:sn+pax,bid=pbx==-1?bv:tn+pbx;
	int &ret=memst[aid][bid];
	if(ret==-1) {
		ret=0;
		for(int ax=shead[av];ax!=-1;ax=snxt[ax]) if(pax==-1||(ax^1)!=pax) {
			int aw=sto[ax];
			for(int bx=thead[bv];bx!=-1;bx=tnxt[bx]) if(pbx==-1||(bx^1)!=pbx) {
				int bw=tto[bx];
				calcst(aw,ax,bw,bx);
			}
		}
		int bx1=-1,nbx1=0,bx2=-1,nbx2=0; nz=0;
		for(int bx=thead[bv];bx!=-1;bx=tnxt[bx]) if(pbx==-1||(bx^1)!=pbx) {
			if(tsz[bx]==1) bx1=bx,nbx1++; else if(tsz[bx]==2) bx2=bx,nbx2++; else z[nz++]=bx;
		}
		int n=(nbx1+1)*(nbx2+1)*(1<<nz);
		REP(i,n) dp[i]=0; dp[0]=1;
		for(int ax=shead[av];ax!=-1;ax=snxt[ax]) if(pax==-1||(ax^1)!=pax) {
			int aw=sto[ax];
			REP(j,nz+2) {
				int bx=j<nz?z[j]:j==nz?bx1:bx2; if(bx==-1) continue; int bw=tto[bx];
				int cur=calcst(aw,ax,bw,bx);
				for(int k1=nbx1;k1>=0;--k1) for(int k2=nbx2;k2>=0;--k2) for(int kz=(1<<nz)-1;kz>=0;--kz) {
					int k=k1+(nbx1+1)*(k2+(nbx2+1)*kz); if(dp[k]==0) continue;
					int nk1=k1,nk2=k2,nkz=kz,times=1;
					if(j<nz) if(kz&(1<<j)) continue; else nkz|=1<<j;
					if(j==nz) if(k1==nbx1) continue; else ++nk1,times*=nbx1-k1;
					if(j==nz+1) if(k2==nbx2) continue; else ++nk2,times*=nbx2-k2;
					int nk=nk1+(nbx1+1)*(nk2+(nbx2+1)*nkz);
					dp[nk]=(dp[nk]+(ll)dp[k]*cur*times)%MOD;
				}
			}
		}
		ret=dp[n-1];
		//printf("calcst(%d,%d,%d,%d)=%d\n",av+1,pax==-1?0:sto[pax^1]+1,bv+1,pbx==-1?0:tto[pbx^1]+1,ret);
	}
	return ret;
}
int calctt(int av,int pax,int bv,int pbx) {
	int aid=pax==-1?av:tn+pax,bid=pbx==-1?bv:tn+pbx;
	int &ret=memtt[aid][bid];
	if(ret==-1) {
		ret=0;
		for(int ax=thead[av];ax!=-1;ax=tnxt[ax]) if(pax==-1||(ax^1)!=pax) {
			int aw=tto[ax];
			for(int bx=thead[bv];bx!=-1;bx=tnxt[bx]) if(pbx==-1||(bx^1)!=pbx) {
				int bw=tto[bx];
				calctt(aw,ax,bw,bx);
			}
		}
		int bx1=-1,nbx1=0,bx2=-1,nbx2=0; nz=0;
		for(int bx=thead[bv];bx!=-1;bx=tnxt[bx]) if(pbx==-1||(bx^1)!=pbx) {
			if(tsz[bx]==1) bx1=bx,nbx1++; else if(tsz[bx]==2) bx2=bx,nbx2++; else z[nz++]=bx;
		}
		int n=(nbx1+1)*(nbx2+1)*(1<<nz);
		REP(i,n) dp[i]=0; dp[0]=1;
		for(int ax=thead[av];ax!=-1;ax=tnxt[ax]) if(pax==-1||(ax^1)!=pax) {
			int aw=tto[ax];
			REP(j,nz+2) {
				int bx=j<nz?z[j]:j==nz?bx1:bx2; if(bx==-1) continue; int bw=tto[bx];
				int cur=calctt(aw,ax,bw,bx);
				for(int k1=nbx1;k1>=0;--k1) for(int k2=nbx2;k2>=0;--k2) for(int kz=(1<<nz)-1;kz>=0;--kz) {
					int k=k1+(nbx1+1)*(k2+(nbx2+1)*kz); if(dp[k]==0) continue;
					int nk1=k1,nk2=k2,nkz=kz,times=1;
					if(j<nz) if(kz&(1<<j)) continue; else nkz|=1<<j;
					if(j==nz) if(k1==nbx1) continue; else ++nk1,times*=nbx1-k1;
					if(j==nz+1) if(k2==nbx2) continue; else ++nk2,times*=nbx2-k2;
					int nk=nk1+(nbx1+1)*(nk2+(nbx2+1)*nkz);
					dp[nk]=(dp[nk]+(ll)dp[k]*cur*times)%MOD;
				}
			}
		}
		ret=dp[n-1];
		//printf("calctt(%d,%d,%d,%d)=%d\n",av+1,pax==-1?0:tto[pax^1]+1,bv+1,pbx==-1?0:tto[pbx^1]+1,ret);
	}
	return ret;
}

int mypow(int x,int n) { int ret=1; while(true) { if(n&1) ret=(ll)ret*x%MOD; if((n>>=1)==0) return ret; x=(ll)x*x%MOD; } }
void run() {
	scanf("%d",&sn); REP(i,sn) shead[i]=-1; REP(i,sn-1) { int a,b; scanf("%d%d",&a,&b); --a,--b; snxt[2*i+0]=shead[a],shead[a]=2*i+0,sto[2*i+0]=b,snxt[2*i+1]=shead[b],shead[b]=2*i+1,sto[2*i+1]=a; }
	scanf("%d",&tn); REP(i,tn) thead[i]=-1; REP(i,tn-1) { int a,b; scanf("%d%d",&a,&b); --a,--b; tnxt[2*i+0]=thead[a],thead[a]=2*i+0,tto[2*i+0]=b,tnxt[2*i+1]=thead[b],thead[b]=2*i+1,tto[2*i+1]=a; }

	memset(tsz,0,sizeof(tsz)); REP(i,2*(tn-1)) calctsz(i);
	//REP(i,2*(tn-1)) printf("%d->%d = %d\n",tto[i^1]+1,tto[i]+1,tsz[i]);
	int cnt=0; memset(memst,-1,sizeof(memst));
	REP(i,sn) {
		int cur=calcst(i,-1,0,-1);
		if((cnt+=cur)>=MOD) cnt-=MOD;
	}
	int times=0; memset(memtt,-1,sizeof(memtt));
	REP(i,tn) {
		int cur=calctt(i,-1,0,-1);
		if((times+=cur)>=MOD) times-=MOD;
	}
	int ret=(ll)cnt*mypow(times,MOD-2)%MOD;
	printf("%d\n",ret);
}

int main() {
	run();
	return 0;
}


#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#include <cstring>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <list>
#include <cassert>
#include <ctime>
#include <climits>
using namespace std;

#define PB push_back
#define MP make_pair
#define SZ(v) ((int)(v).size())
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n) FOR(i,0,n)
#define FORE(i,a,b) for(int i=(a);i<=(b);++i)
#define REPE(i,n) FORE(i,0,n)
#define FORSZ(i,a,v) FOR(i,a,SZ(v))
#define REPSZ(i,v) REP(i,SZ(v))
typedef long long ll;
typedef unsigned long long ull;
ll gcd(ll a,ll b) { return b==0?a:gcd(b,a%b); }

const int MAXSN=1000;
const int MAXSM=MAXSN-1;
const int MAXTN=12;
const int MAXTM=MAXTN-1;
const int MOD=1000000007;

int sn;
int shead[MAXSN],snxt[2*MAXSM],sto[2*MAXSM];
int tn;
int thead[MAXTN],tnxt[2*MAXTM],tto[2*MAXTM];

int tsz[2*MAXTM];
int calctsz(int x) {
	if(tsz[x]!=0) return tsz[x]; else tsz[x]=1;
	int at=tto[x];
	for(int y=thead[at];y!=-1;y=tnxt[y]) if((y^1)!=x) tsz[x]+=calctsz(y);
	return tsz[x];
}

int memst[MAXSN+2*MAXSM][MAXTN+2*MAXTM];
int memtt[MAXTN+2*MAXTM][MAXTN+2*MAXTM];
int z[MAXTN],nz;
int dp[1<<MAXTN];
int calcst(int av,int pax,int bv,int pbx) {
	int aid=pax==-1?av:sn+pax,bid=pbx==-1?bv:tn+pbx;
	int &ret=memst[aid][bid];
	if(ret==-1) {
		ret=0;
		for(int ax=shead[av];ax!=-1;ax=snxt[ax]) if(pax==-1||(ax^1)!=pax) {
			int aw=sto[ax];
			for(int bx=thead[bv];bx!=-1;bx=tnxt[bx]) if(pbx==-1||(bx^1)!=pbx) {
				int bw=tto[bx];
				calcst(aw,ax,bw,bx);
			}
		}
		int bx1=-1,nbx1=0,bx2=-1,nbx2=0; nz=0;
		for(int bx=thead[bv];bx!=-1;bx=tnxt[bx]) if(pbx==-1||(bx^1)!=pbx) {
			if(tsz[bx]==1) bx1=bx,nbx1++; else if(tsz[bx]==2) bx2=bx,nbx2++; else z[nz++]=bx;
		}
		int n=(nbx1+1)*(nbx2+1)*(1<<nz);
		REP(i,n) dp[i]=0; dp[0]=1;
		for(int ax=shead[av];ax!=-1;ax=snxt[ax]) if(pax==-1||(ax^1)!=pax) {
			int aw=sto[ax];
			for(int k1=nbx1;k1>=0;--k1) for(int k2=nbx2;k2>=0;--k2) for(int kz=(1<<nz)-1;kz>=0;--kz) {
				int k=k1+(nbx1+1)*(k2+(nbx2+1)*kz); if(dp[k]==0) continue;
				REP(j,nz+2) {
					int nk1=k1,nk2=k2,nkz=kz,times=1;
					int bx=j<nz?z[j]:j==nz?bx1:bx2; if(bx==-1) continue; int bw=tto[bx];
					int cur=calcst(aw,ax,bw,bx);
					if(j<nz) if(kz&(1<<j)) continue; else nkz|=1<<j;
					if(j==nz) if(k1==nbx1) continue; else ++nk1,times*=nbx1-k1;
					if(j==nz+1) if(k2==nbx2) continue; else ++nk2,times*=nbx2-k2;
					int nk=nk1+(nbx1+1)*(nk2+(nbx2+1)*nkz);
					dp[nk]=(dp[nk]+(ll)dp[k]*cur*times)%MOD;
				}
			}
		}
		ret=dp[n-1];
		//printf("calcst(%d,%d,%d,%d)=%d\n",av+1,pax==-1?0:sto[pax^1]+1,bv+1,pbx==-1?0:tto[pbx^1]+1,ret);
	}
	return ret;
}
int calctt(int av,int pax,int bv,int pbx) {
	int aid=pax==-1?av:tn+pax,bid=pbx==-1?bv:tn+pbx;
	int &ret=memtt[aid][bid];
	if(ret==-1) {
		ret=0;
		for(int ax=thead[av];ax!=-1;ax=tnxt[ax]) if(pax==-1||(ax^1)!=pax) {
			int aw=tto[ax];
			for(int bx=thead[bv];bx!=-1;bx=tnxt[bx]) if(pbx==-1||(bx^1)!=pbx) {
				int bw=tto[bx];
				calctt(aw,ax,bw,bx);
			}
		}
		int bx1=-1,nbx1=0,bx2=-1,nbx2=0; nz=0;
		for(int bx=thead[bv];bx!=-1;bx=tnxt[bx]) if(pbx==-1||(bx^1)!=pbx) {
			if(tsz[bx]==1) bx1=bx,nbx1++; else if(tsz[bx]==2) bx2=bx,nbx2++; else z[nz++]=bx;
		}
		int n=(nbx1+1)*(nbx2+1)*(1<<nz);
		REP(i,n) dp[i]=0; dp[0]=1;
		for(int ax=thead[av];ax!=-1;ax=tnxt[ax]) if(pax==-1||(ax^1)!=pax) {
			int aw=tto[ax];
			for(int k1=nbx1;k1>=0;--k1) for(int k2=nbx2;k2>=0;--k2) for(int kz=(1<<nz)-1;kz>=0;--kz) {
				int k=k1+(nbx1+1)*(k2+(nbx2+1)*kz); if(dp[k]==0) continue;
				REP(j,nz+2) {
					int nk1=k1,nk2=k2,nkz=kz,times=1;
					int bx=j<nz?z[j]:j==nz?bx1:bx2; if(bx==-1) continue; int bw=tto[bx];
					int cur=calctt(aw,ax,bw,bx);
					if(j<nz) if(kz&(1<<j)) continue; else nkz|=1<<j;
					if(j==nz) if(k1==nbx1) continue; else ++nk1,times*=nbx1-k1;
					if(j==nz+1) if(k2==nbx2) continue; else ++nk2,times*=nbx2-k2;
					int nk=nk1+(nbx1+1)*(nk2+(nbx2+1)*nkz);
					dp[nk]=(dp[nk]+(ll)dp[k]*cur*times)%MOD;
				}
			}
		}
		ret=dp[n-1];
		//printf("calctt(%d,%d,%d,%d)=%d\n",av+1,pax==-1?0:tto[pax^1]+1,bv+1,pbx==-1?0:tto[pbx^1]+1,ret);
	}
	return ret;
}

int mypow(int x,int n) { int ret=1; while(true) { if(n&1) ret=(ll)ret*x%MOD; if((n>>=1)==0) return ret; x=(ll)x*x%MOD; } }
void run() {
	scanf("%d",&sn); REP(i,sn) shead[i]=-1; REP(i,sn-1) { int a,b; scanf("%d%d",&a,&b); --a,--b; snxt[2*i+0]=shead[a],shead[a]=2*i+0,sto[2*i+0]=b,snxt[2*i+1]=shead[b],shead[b]=2*i+1,sto[2*i+1]=a; }
	scanf("%d",&tn); REP(i,tn) thead[i]=-1; REP(i,tn-1) { int a,b; scanf("%d%d",&a,&b); --a,--b; tnxt[2*i+0]=thead[a],thead[a]=2*i+0,tto[2*i+0]=b,tnxt[2*i+1]=thead[b],thead[b]=2*i+1,tto[2*i+1]=a; }

	memset(tsz,0,sizeof(tsz)); REP(i,2*(tn-1)) calctsz(i);
	//REP(i,2*(tn-1)) printf("%d->%d = %d\n",tto[i^1]+1,tto[i]+1,tsz[i]);
	int cnt=0; memset(memst,-1,sizeof(memst));
	REP(i,sn) {
		int cur=calcst(i,-1,0,-1);
		if((cnt+=cur)>=MOD) cnt-=MOD;
	}
	int times=0; memset(memtt,-1,sizeof(memtt));
	REP(i,tn) {
		int cur=calctt(i,-1,0,-1);
		if((times+=cur)>=MOD) times-=MOD;
	}
	int ret=(ll)cnt*mypow(times,MOD-2)%MOD;
	//printf("cnt=%d times=%d\n",cnt,times);
	printf("%d\n",ret);
}

int main() {
	run();
	return 0;
}


#include<bits/stdc++.h>
#define ll long long
#define ull unsigned ll
#define uint unsigned
#define pii pair<int,int>
#define pll pair<ll,ll>
#define IT iterator
#define PB push_back
#define fi first
#define se second
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);i++)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);i--)
#define CLR(a,v) memset(a,v,sizeof(a));
#define CPY(a,b) memcpy(a,b,sizeof(a));
#define debug puts("wzpakking")
#define y1 ysghysgsygsh
using namespace std;
const int mo=1000000007;
const int N=1005;
int vis[N][1<<12],T;
int f[N][1<<12];
struct Tree{
	vector<int> e[N],c[N];
	int sz[N],hsh[N],n;
	void init(){
		scanf("%d",&n);
		For(i,1,n-1){
			int x,y;
			scanf("%d%d",&x,&y);
			e[x].PB(y); e[y].PB(x);
		}
	}
	void dfs(int x,int fa){
		hsh[x]=0;
		c[x].resize(0);
		for (auto i:e[x]) if (i!=fa)
			c[x].PB(i),dfs(i,x),hsh[x]|=1<<(i-1);
	}
}a,b;
int dfs(int x,int y,int v){
	//cout<<x<<' '<<y<<' '<<v<<endl;
	if (y<0) return !v;
	int to=a.c[x][y];
	if (vis[to][v]==T)
		return f[to][v];
	vis[to][v]=T;
	int &ans=f[to][v];
	ans=dfs(x,y-1,v);
	For(k,0,b.n-1) if (v&(1<<k))
		ans=(ans+1ll*dfs(x,y-1,v^(1<<k))*dfs(to,a.c[to].size()-1,b.hsh[k+1]))%mo;
	return ans;
}
int count(){
	int ans=0;
	a.dfs(1,0);
	For(i,1,b.n){
		b.dfs(i,0); ++T;
		For(j,1,a.n) ans=(ans+dfs(j,a.c[j].size()-1,b.hsh[i]))%mo;
	}
	return ans;
}
int Inv(int x){
	return x<=1?1:1ll*Inv(mo%x)*(mo-mo/x)%mo;
}
int main(){
	a.init();
	b.init();
	int ans=count();
	a=b;
	int Ans=count();
	//cout<<ans<<' '<<Ans<<endl;
	printf("%lld\n",1ll*ans*Inv(Ans)%mo);
}


#include<bits/stdc++.h>
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(int i=(a);i>=(b);--i)
#define eb emplace_back
#define ff first
#define ss second

using namespace std;
typedef unsigned long long ull;

const int P=131;
const int md=1e9+7;

int n,m,xs;
int sz[15],f[2003][15],g[2003][1<<12|3],st[15],prt[15],bin[15];
ull pw[15];
vector<int>e1[2003],e2[15];
struct Ha{
  static const int md=2999999;
  ull key[md];
  void Ins(ull t){
    int s=t%md;
    while(key[s]&&key[s]!=t)if(++s==md)s=0;
    key[s]=t;
  }
  bool Check(ull t){
    int s=t%md;
    while(key[s]&&key[s]!=t)if(++s==md)s=0;
    return key[s]==t;
  }
}H;

inline int inc(int x,int y){return x+y>=md?x+y-md:x+y;}
inline int mul(int x,int y){return (long long)x*y%md;}
inline void cinc(int&x,int y){x=inc(x,y);}
inline void cmul(int&x,int y){x=mul(x,y);}
inline int Qp(int x,int k,int m=1){for(;k;k>>=1,cmul(x,x))if(k&1)cmul(m,x);return m;}

ull Dfs(int u,int fa){
	sz[u]=1,prt[u]=fa;
	vector<pair<ull,int> >ve;
	for(int v:e2[u]){
		if(v==fa)continue;
		ve.eb(Dfs(v,u),v);
		sz[u]+=sz[v];
	}
	sort(ve.begin(),ve.end());
	ull h='(';
	int cnt=1;ull pre=0;
	for(auto x:ve){
		if(x.ff==pre)++cnt;
		else cnt=1;
		h=h*pw[sz[x.ss]]+x.ff;
		pre=x.ff;
		cmul(xs,cnt);
	}
	return h*P+')';
}

void Dfs1(int u,int fa){
	for(int v:e1[u]){
		if(v==fa)continue;
		Dfs1(v,u);
	}
	For(i,1,m){
		*st=0;
		for(int v:e2[i])if(v!=prt[i])st[++*st]=v;
		g[0][0]=1;
		int S=bin[*st]-1,now=0;
		for(int v:e1[u]){
			++now;
			For(T,0,S)g[now][T]=g[now-1][T];
			For(T,0,S){
				For(k,1,*st)if(T&bin[k-1]){
					cinc(g[now][T],mul(g[now-1][T^bin[k-1]],f[v][st[k]]));
				}
			}
		}
		cinc(f[u][i],g[now][S]);
		For(j,0,now)For(T,0,S)g[j][T]=0;
	}
}

int main(){
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n;
	For(i,2,n){
		int x,y;cin>>x>>y;
		e1[x].eb(y),e1[y].eb(x);
	}
	cin>>m;
	For(i,2,m){
		int x,y;cin>>x>>y;
		e2[x].eb(y),e2[y].eb(x);
	}
	pw[0]=1;
	For(i,1,m)pw[i]=pw[i-1]*P;
	bin[0]=1;
	For(i,1,m)bin[i]=bin[i-1]<<1;

	int ans=0;
	For(i,1,m){
		xs=1;
		ull h=Dfs(i,0);
		if(H.Check(h))continue;
		H.Ins(h);
		Dfs1(1,0);
		xs=Qp(xs,md-2);
		For(j,1,n)cinc(ans,mul(xs,f[j][i]));
		For(j,0,n)For(k,0,m)f[j][k]=0;
	}
	cout<<ans<<'\n';
return 0; }


#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cctype>
#include<vector>
#include<map>
#include<queue>
#include<algorithm>
using namespace std;

const int N = 1020 , M = 15;
const int Mod = 1000000007;
int n,m,t1,t2,Hea[N],Head[N];

int g[1<<M],p[1<<M],ans;

map < int , vector<int> > List;
map < int , int > f[N];
struct edge { int ver,next; } e1[N*2],e2[N*2];
inline void insert(int x,int y,int id)
{
    if ( id == 1 )
        e1[++t1] = (edge){y,Hea[x]} , Hea[x] = t1,
        e1[++t1] = (edge){x,Hea[y]} , Hea[y] = t1;
    if ( id == 2 )
        e2[++t2] = (edge){y,Head[x]} , Head[x] = t2,
        e2[++t2] = (edge){x,Head[y]} , Head[y] = t2;
}
inline int read(void)
{
    int x = 0 , w = 0; char ch = ' ';
    while ( !isdigit(ch) ) w |= ch=='-' , ch = getchar();
    while ( isdigit(ch) ) x = x*10 + ch-48 , ch = getchar();
    return w ? -x : x;
}
inline void input(void)
{
    n = read();
    for (int i=1;i<n;i++)
        insert( read() , read() , 1 );
    m = read();
    for (int i=1;i<m;i++)
        insert( read() , read() , 2 );
}
inline int lenth(int x) { return 32 - __builtin_clz(x); }
inline void connect(int &x,int y) { x = x << lenth(y) | y; }
inline int Ergodic(int x,int fa)
{
    int S = 1;
    vector < int > cur;
    for (int i=Head[x];i;i=e2[i].next)
    {
        int y = e2[i].ver;
        if ( y == fa ) continue;
        cur.push_back( Ergodic( y , x ) );
    }
    sort( cur.begin() , cur.end() );
    vector < int > :: iterator it;
    for (it=cur.begin();it!=cur.end();it++)
        connect( S , *it );
    S <<= 1;
    if ( !List.count( S ) ) List[S] = cur;
    return S;
}
inline void dp(int x,int fa)
{
    vector < int > ch;
    for (int i=Hea[x];i;i=e1[i].next)
    {
        int y = e1[i].ver;
        if ( y == fa ) continue;
        ch.push_back( y ) , dp( y , x );
    }
    map < int , vector< int > > :: iterator it;
    for (it=List.begin();it!=List.end();it++)
    {
        vector < int > cur = it -> second;
        int S = it -> first , len = cur.size();
        memset( g , 0 , sizeof g );
        g[0] = 1;
        for (int i=0;i<ch.size();i++)
        {
            memcpy( p , g , sizeof g );
            for (int j=0;j<len;j++)
            {
                int val = f[ch[i]][cur[j]];
                if ( val == 0 ) continue;
                for (int k=(1<<len)-1;k>=0;k--)
                    if ( g[k] && !( k >> j & 1 ) && ( j == 0 || cur[j] != cur[j-1] || ( k >> (j-1) & 1 ) ) )
                        p[k|(1<<j)] = ( p[k|(1<<j)] + 1LL * g[k] * val % Mod ) % Mod;
            }
            memcpy( g , p , sizeof p );
        }
        if ( g[(1<<len)-1] )
        {
            f[x][S] = g[(1<<len)-1];
            if ( lenth(S) == (m<<1) )
                ans = ( ans + f[x][S] ) % Mod;
        }
    }
}
int main()
{
    input();
    for (int i=1;i<=m;i++)
        Ergodic( i , 0 );
    dp( 1 , 0 );
    printf("%d\n",ans);
    return 0;
}


#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=(a);i<=(b);++i)
#define of(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
const int maxn=2111,p=1e9+7;
struct tree{
	int son[maxn][maxn],cnt[maxn],s[maxn],n;
	vector<int>v[maxn];
	void read(){cin>>n;fo(i,1,n-1){int x,y;cin>>x>>y;v[x].push_back(y);v[y].push_back(x);}}
	void dfs(int x,int fa){
		cnt[x]=0;s[x]=0;
		for(int y:v[x]){
			if(y==fa)continue;
			son[x][++cnt[x]]=y;s[x]|=(1<<(y-1));
			dfs(y,x);
		}
	}
}a,b;
int dp(int x,int now,int S){
	if(!now||!S)return !S;
	int ret=dp(x,now-1,S);//这个点当前now儿子不匹配
	for(int y=a.son[x][now],k=0;k<b.n;++k)
		if(S>>k&1)ret=(ret+1ll*dp(x,now-1,S-(1<<k))*dp(y,a.cnt[y],b.s[k+1]))%p;
	return ret;
}
int poww(int a,int b){
	int ans=1;
	while(b){if(b&1)ans=1ll*ans*a%p;b>>=1;a=1ll*a*a%p;}return ans;
}
int main(){
	//freopen("1.in","r",stdin);
	a.read();b.read();
	a.dfs(1,0);
	int ans1=0,ans2=0;
	fo(i,1,b.n){
		b.dfs(i,0);
		fo(j,1,a.n)ans1=(ans1+dp(j,a.cnt[j],b.s[i]))%p;
	}
	a=b;
	a.dfs(1,0);
	fo(i,1,b.n){
		b.dfs(i,0);
		fo(j,1,a.n)ans2=(ans2+dp(j,a.cnt[j],b.s[i]))%p;
	}
	ans1=1ll*ans1*poww(ans2,p-2)%p;
	cout<<ans1;
}
//g++ 1.cpp -g -o 1 -std=c++11


#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=(a);i<=(b);++i)
#define of(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
const int maxn=2111,p=1e9+7;
struct tree{
	int son[maxn][maxn],cnt[maxn],s[maxn],n;
	vector<int>v[maxn];
	void read(){cin>>n;fo(i,1,n-1){int x,y;cin>>x>>y;v[x].push_back(y);v[y].push_back(x);}}
	void dfs(int x,int fa){
		cnt[x]=0;s[x]=0;
		for(int y:v[x]){
			if(y==fa)continue;
			son[x][++cnt[x]]=y;s[x]|=(1<<(y-1));
			dfs(y,x);
		}
	}
}a,b;
int f[maxn][5000];
int dp(int x,int now,int S){
	if(!now||!S)return !S;
	int &ret=f[a.son[x][now]][S];
	if(ret)return ret-1;
	ret=dp(x,now-1,S);//这个点当前now儿子不匹配
	for(int y=a.son[x][now],k=0;k<b.n;++k)
		if(S>>k&1)ret=(ret+1ll*dp(x,now-1,S-(1<<k))*dp(y,a.cnt[y],b.s[k+1]))%p;
	return ret++;
}
int poww(int a,int b){
	int ans=1;
	while(b){if(b&1)ans=1ll*ans*a%p;b>>=1;a=1ll*a*a%p;}return ans;
}
int main(){
	//reopen("1.in","r",stdin);
	a.read();b.read();
	a.dfs(1,0);
	int ans1=0,ans2=0;
	fo(i,1,b.n){
		b.dfs(i,0);
		fo(j,1,a.n)ans1=(ans1+dp(j,a.cnt[j],b.s[i]))%p;
		memset(f,0,sizeof(f));
	}
	a=b;
	a.dfs(1,0);
	fo(i,1,b.n){
		b.dfs(i,0);
		fo(j,1,a.n)ans2=(ans2+dp(j,a.cnt[j],b.s[i]))%p;
		memset(f,0,sizeof(f));
	}
	ans1=1ll*ans1*poww(ans2,p-2)%p;
	cout<<ans1;
}
//g++ 1.cpp -g -o 1 -std=c++11


/*
设计状态f[x][i][s]表示a树中x点 倒着考虑到第i个儿子 b中这一层儿子未匹配的集合为s的方案数
转移时枚举一个儿子和s中哪个点匹配 加上f[x][i-1][s-(1<<k)]和那个儿子子树和b树中对应点那一层的点集的匹配方案数即可
最后再除以b和b自己匹配的方案数
*/
#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=(a);i<=(b);++i)
#define of(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
const int maxn=2111,p=1e9+7;
struct tree{
	int son[maxn][maxn],cnt[maxn],s[maxn],n;
	vector<int>v[maxn];
	void read(){cin>>n;fo(i,1,n-1){int x,y;cin>>x>>y;v[x].push_back(y);v[y].push_back(x);}}
	void dfs(int x,int fa){
		cnt[x]=0;s[x]=0;
		for(int y:v[x]){
			if(y==fa)continue;
			son[x][++cnt[x]]=y;s[x]|=(1<<(y-1));
			dfs(y,x);
		}
	}
}a,b;
int f[maxn][5000];
int dp(int x,int now,int S){
	if(!now||!S)return !S;
	int &ret=f[a.son[x][now]][S];
	if(ret)return ret-1;
	ret=dp(x,now-1,S);//这个点当前now儿子不匹配
	for(int y=a.son[x][now],k=0;k<b.n;++k)
		if(S>>k&1)ret=(ret+1ll*dp(x,now-1,S-(1<<k))*dp(y,a.cnt[y],b.s[k+1]))%p;//枚举第j个孩子和k匹配 将前面几个孩子和剩下的状态匹配与第j个孩子的子树和k的子树匹配的方案数
	return ret++;
}
int poww(int a,int b){
	int ans=1;
	while(b){if(b&1)ans=1ll*ans*a%p;b>>=1;a=1ll*a*a%p;}return ans;
}
int main(){
	//reopen("1.in","r",stdin);
	a.read();b.read();
	a.dfs(1,0);
	int ans1=0,ans2=0;
	fo(i,1,b.n){
		b.dfs(i,0);
		fo(j,1,a.n)ans1=(ans1+dp(j,a.cnt[j],b.s[i]))%p;
		memset(f,0,sizeof(f));
	}
	a=b;
	a.dfs(1,0);
	fo(i,1,b.n){
		b.dfs(i,0);
		fo(j,1,a.n)ans2=(ans2+dp(j,a.cnt[j],b.s[i]))%p;
		memset(f,0,sizeof(f));
	}
	ans1=1ll*ans1*poww(ans2,p-2)%p;
	cout<<ans1;
}
//g++ 1.cpp -g -o 1 -std=c++11


#include <set>
#include <map>
#include <cmath>
#include <ctime>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <iomanip>
#include <iostream>
#include <algorithm>
#define PR pair
#define fi first
#define se second
#define mk make_pair
#define pb push_back
#define REP(i, x, y)   for(int i = (int)(x); i <= (int)(y); i++)
#define FOR(i, x, y)   for(int i = (int)(x); i <  (int)(y); i++)
#define PER(i ,x, y)   for(int i = (int)(x); i >= (int)(y); i--)
#define CH	         ch = getchar()
#define Exit(...)    printf(__VA_ARGS__), exit(0)
#define dln()        fprintf(stderr,"\n")
#define dprintf(...) fprintf(stderr,__VA_ARGS__)
using namespace std;
typedef double	  db;
typedef long long LL;
typedef vector<int> VI;
typedef vector<VI > VII;
typedef PR<int,int> PII;
typedef vector<PII> VPI;
const	int inf=2e9;
const	LL Inf=1e10;
const	int P=1e9+7;
const	int N=1005;
const	int M=14;

inline LL IN(){
	LL x = 0;
	int ch = 0, f = 0;
	for (CH; ch != -1 && (ch < 48 || ch > 57); CH) f = (ch == '-');
	for (; ch >= 48 && ch <= 57; CH) x = (x << 1) + (x << 3) + ch - '0';
	return f ? (-x) : x;
}
template<typename T> inline int chkmin(T &a, const T &b){if(b < a) return a = b, 1; return 0;}
template<typename T> inline int chkmax(T &a, const T &b){if(b > a) return a = b, 1; return 0;}

void renew(int &x, const int &y){
	x += y;
	if(x >= P) x -= P;
	if(x <  0) x += P;
}

int Pow(int x, int y, int p){
	int a = 1;
	for (; y; y >>= 1, x = (LL)x * x %p) if(y & 1) a=(LL)a * x%p;
	return a;
}

int dp[N][M * M], tot;
map<VI, int> mps;
int sz_info[N], chd_info[N];
VI chd_hash[M * M];
VI e[N], xe[N];

PII dfs(int x, int y){
	VI s;
	int SZ = 1;
	for(auto v : xe[x]){
		if(v == y) continue;
		PII ret = dfs(v, x);
		SZ += ret.se;
		s.pb(ret.fi);
	}
	sort(s.begin(), s.end());
	int &v = mps[s];
	if(!v){
		v = ++tot;
		sz_info[tot] = SZ;
		chd_info[tot] = s.size();
		chd_hash[tot] = s;
	}
	return PII(v, SZ);
}

int m, n;
map<VI, int> f, g;

int ans, ID[N]; VI Has;
void calc(int x, int y){
	int sn = 0;
	for(auto v : e[x]){
		if(v == y) continue;
		calc(v, x);
		++sn;
	}
	REP(stat, 1, tot){
		int tsz = chd_info[stat];
		if(sn < tsz) continue;
		int cnt = 0;
		f.clear();
		FOR(i, 0, tsz){
			int z = chd_hash[stat][i];
			if(ID[z] == -1){
				ID[z] = cnt;
				Has.pb(0);
				cnt ++;
			}
			++Has.back();
		}
		VI NUL(cnt, 0);
		f[NUL] = 1;
		for(auto son : e[x]){
			if(son == y) continue;
			g = f;
			FOR(j, 0, tsz){
				int v = chd_hash[stat][j], sv = v;
				if(j && v == chd_hash[stat][j - 1]) continue;
				v = ID[v];
				for(const auto &w : f){
					auto st = w.fi;
					int ways = (LL)w.se * dp[son][sv] % P;
					if(st[v] == Has[v]) continue;
					st[v] ++;
					renew(g[st], ways);
				}
			}
			f = g;
		}
		dp[x][stat] = f[Has];
		if(sz_info[stat] == m){
			renew(ans, dp[x][stat]);
		}
		Has.clear();
		FOR(i, 0, tsz) ID[chd_hash[stat][i]] = -1;
	}
}

int main(){
	scanf("%d", &n);
	REP(i, 1, n - 1){
		int x, y;
		scanf("%d%d", &x, &y);
		e[x].pb(y);
		e[y].pb(x);
	}
	scanf("%d", &m);
	REP(i, 1, m - 1){
		int x, y;
		scanf("%d%d", &x, &y);
		xe[x].pb(y);
		xe[y].pb(x);
	}
	REP(i, 1, m) dfs(i, 0);
	memset(ID, -1, sizeof ID);
	calc(1, 0);
	printf("%d\n", ans);
	return 0;
}


/*
 * ç‰ˆæƒå£°æ˜Žï¼šæœ¬æ–‡ä¸ºCSDNåšä¸»ã€Œwxh010910ã€çš„åŽŸåˆ›æ–‡ç« ï¼Œéµå¾ªCC 4.0 BY-SAç‰ˆæƒåè®®ï¼Œè½¬è½½è¯·é™„ä¸ŠåŽŸæ–‡å‡ºå¤„é“¾æŽ¥åŠæœ¬å£°æ˜Žã€‚
 * åŽŸæ–‡é“¾æŽ¥ï¼šhttps://blog.csdn.net/wxh010910/java/article/details/54784089
 */

#include <bits/stdc++.h>

using namespace std;

const int MAXN = 1001;
const int MAXV = 1 << 12;
const int mod = 1e9 + 7;

inline int Pow(int x, int y)
{
	int s = 1;
	for (; y; y >>= 1, x = 1ll * x * x % mod)
		if (y & 1)
			s = 1ll * s * x % mod;
	return s;
}

inline int inv(int x) { return Pow(x, mod - 2); }

struct edge
{
	int to, nxt;
};

struct tree
{
	edge e[MAXN << 1];
	int n, cnt;
	int head[MAXN], son[MAXN][MAXN], size[MAXN], bit[MAXN];
	inline void addedge(int x, int y)
	{
		e[++cnt].to = y;
		e[cnt].nxt = head[x];
		head[x] = cnt;
	}
	inline void read()
	{
		scanf("%d", &n);
		for (int i = 1; i < n; i++)
		{
			int x, y;
			scanf("%d%d", &x, &y);
			addedge(x, y);
			addedge(y, x);
		}
	}
	inline void dfs(int x, int fa)
	{
		size[x] = bit[x] = 0;
		for (int i = head[x]; i; i = e[i].nxt)
			if (e[i].to ^ fa)
				dfs(son[x][++size[x]] = e[i].to, x), bit[x] |= 1 << e[i].to - 1;
	}
} S, T;

int dp[MAXN][MAXV], ans, ans2;

bool vis[MAXN][MAXV];

inline int dfs(int f, int y, int V)
{
	if (!y)
		return !V;
	int x = S.son[f][y];
	if (vis[x][V])
		return dp[x][V];
	vis[x][V] = 1;
	int &ret = dp[x][V];
	ret = dfs(f, y - 1, V);
	for (int i = 0; i < T.n; i++)
		if (V >> i & 1)
			ret = (1ll * dfs(f, y - 1, V ^ (1 << i)) * dfs(x, S.size[x], T.bit[i + 1]) + ret) % mod;
	return ret;
}

int main()
{
	//freopen("tree.in", "r", stdin);
	//freopen("tree.out", "w", stdout);
	S.read();
	T.read();
	S.dfs(1, 0);
	for (int i = 1; i <= T.n; i++)
	{
		memset(dp, 0, sizeof dp);
		memset(vis, 0, sizeof vis);
		T.dfs(i, 0);
		for (int j = 1; j <= S.n; j++)
			(ans += dfs(j, S.size[j], T.bit[i])) %= mod;
	}
	S = T;
	S.dfs(1, 0);
	for (int i = 1; i <= T.n; i++)
	{
		memset(dp, 0, sizeof dp);
		memset(vis, 0, sizeof vis);
		T.dfs(i, 0);
		(ans2 += dfs(1, S.size[1], T.bit[i])) %= mod;
	}
	ans = 1ll * ans * inv(ans2) % mod;
	return printf("%d\n", ans), 0;
}


#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;

const ll N=1010,V=12,mod=1000000007;
ll ans,sum,f[N][1<<V],v[N][1<<V];

namespace IO{
	inline ll read(){
		ll x=0,tmp=1;
		char ch=getchar();
		while(!isdigit(ch)){
			if(ch=='-') tmp=-1;
			ch=getchar();
		}
		while(isdigit(ch)){
			x=(x<<3)+(x<<1)+(ch^48);
			ch=getchar();
		}
		return tmp*x;
	}
}

ll ksm(ll x,ll y){
	if(y==0) return 1;
	ll t=ksm(x,y/2)%mod;
	t=t*t%mod;
	if(y&1) t=t*x%mod;
	return t%mod;
}

struct tree{
	ll n,son[N][N],size[N],bit[N];
	ll ver[N<<1],Next[N<<1],head[N],tot;
	inline void addEdge(ll x,ll y){
		ver[++tot]=y;
		Next[tot]=head[x];
		head[x]=tot;
	}
	inline void read(){
		n=IO::read();
		for(ll i=1; i<n; i++){
			ll x=IO::read(),y=IO::read();
			addEdge(x,y);
			addEdge(y,x);
		}
	}
	void dfs(ll x,ll before){
		size[x]=bit[x]=0;
		for(ll i=head[x]; i; i=Next[i]){
			ll y=ver[i];
			if(y==before) continue;
			son[x][++size[x]]=y;
			dfs(y,x);
			bit[x]|=1<<(y-1);
		}
	}
}S,T;

ll dfs(ll x,ll now,ll val){
	if(!now) return !val;
	ll y=S.son[x][now];
	if(v[y][val]) return f[y][val];
	v[y][val]=1;
	ll &sum=f[y][val]; sum=dfs(x,now-1,val);
	for(ll i=0; i<T.n; i++){
		if(val>>i&1) sum=(sum+dfs(x,now-1,val^(1<<i))*dfs(y,S.size[y],T.bit[i+1]))%mod;
	}
	return sum;
}

int main(){
	S.read(); T.read(); S.dfs(1,0);
	for(ll i=1; i<=T.n; i++){
		memset(f,0,sizeof(f));
		memset(v,0,sizeof(v));
		T.dfs(i,0);
		for(ll j=1; j<=S.n; j++) ans=(ans+dfs(j,S.size[j],T.bit[i]))%mod;
	}
	S=T; S.dfs(1,0);
	for(ll i=1; i<=T.n; i++){
		memset(f,0,sizeof(f));
		memset(v,0,sizeof(v));
		T.dfs(i,0);
		sum=(sum+dfs(1,S.size[1],T.bit[i]))%mod;
	}
	cout<<ans*ksm(sum,mod-2)%mod<<endl;
	return 0;
}


#pragma GCC optimize(2)
#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;

const ll N=1010,V=12,mod=1000000007;
ll ans,sum,f[N][1<<V],v[N][1<<V];

namespace IO{
	inline ll read(){
		ll x=0,tmp=1;
		char ch=getchar();
		while(!isdigit(ch)){
			if(ch=='-') tmp=-1;
			ch=getchar();
		}
		while(isdigit(ch)){
			x=(x<<3)+(x<<1)+(ch^48);
			ch=getchar();
		}
		return tmp*x;
	}
}

ll ksm(ll x,ll y){
	if(y==0) return 1;
	ll t=ksm(x,y/2)%mod;
	t=t*t%mod;
	if(y&1) t=t*x%mod;
	return t%mod;
}

struct tree{
	ll n,son[N][N],size[N],bit[N];
	ll ver[N<<1],Next[N<<1],head[N],tot;
	inline void addEdge(ll x,ll y){
		ver[++tot]=y;
		Next[tot]=head[x];
		head[x]=tot;
	}
	inline void read(){
		n=IO::read();
		for(ll i=1; i<n; i++){
			ll x=IO::read(),y=IO::read();
			addEdge(x,y);
			addEdge(y,x);
		}
	}
	void dfs(ll x,ll before){
		size[x]=bit[x]=0;
		for(ll i=head[x]; i; i=Next[i]){
			ll y=ver[i];
			if(y==before) continue;
			son[x][++size[x]]=y;
			dfs(y,x);
			bit[x]|=1<<(y-1);
		}
	}
}S,T;

ll dfs(ll x,ll now,ll val){
	if(!now) return !val;
	ll y=S.son[x][now];
	if(v[y][val]) return f[y][val];
	v[y][val]=1;
	ll &sum=f[y][val]; sum=dfs(x,now-1,val);
	for(ll i=0; i<T.n; i++){
		if(val>>i&1) sum=(sum+dfs(x,now-1,val^(1<<i))*dfs(y,S.size[y],T.bit[i+1]))%mod;
	}
	return sum;
}

int main(){
	S.read(); T.read(); S.dfs(1,0);
	for(ll i=1; i<=T.n; i++){
		memset(f,0,sizeof(f));
		memset(v,0,sizeof(v));
		T.dfs(i,0);
		for(ll j=1; j<=S.n; j++) ans=(ans+dfs(j,S.size[j],T.bit[i]))%mod;
	}
	S=T; S.dfs(1,0);
	for(ll i=1; i<=T.n; i++){
		memset(f,0,sizeof(f));
		memset(v,0,sizeof(v));
		T.dfs(i,0);
		sum=(sum+dfs(1,S.size[1],T.bit[i]))%mod;
	}
	cout<<ans*ksm(sum,mod-2)%mod<<endl;
	return 0;
}


#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;

const ll N=1010,V=12,mod=1000000007;
ll ans,sum,f[N][1<<V],v[N][1<<V];

namespace IO{
	inline ll read(){
		ll x=0,tmp=1;
		char ch=getchar();
		while(!isdigit(ch)){
			if(ch=='-') tmp=-1;
			ch=getchar();
		}
		while(isdigit(ch)){
			x=(x<<3)+(x<<1)+(ch^48);
			ch=getchar();
		}
		return tmp*x;
	}
}

ll ksm(ll x,ll y){
	if(y==0) return 1;
	ll t=ksm(x,y/2)%mod;
	t=t*t%mod;
	if(y&1) t=t*x%mod;
	return t%mod;
}

struct tree{
	ll n,son[N][N],size[N],bit[N];
	ll ver[N<<1],Next[N<<1],head[N],tot;
	inline void addEdge(ll x,ll y){
		ver[++tot]=y;
		Next[tot]=head[x];
		head[x]=tot;
	}
	inline void read(){
		n=IO::read();
		for(ll i=1; i<n; i++){
			ll x=IO::read(),y=IO::read();
			addEdge(x,y);
			addEdge(y,x);
		}
	}
	void dfs(ll x,ll before){
		size[x]=bit[x]=0;
		for(ll i=head[x]; i; i=Next[i]){
			ll y=ver[i];
			if(y==before) continue;
			son[x][++size[x]]=y;
			dfs(y,x);
			bit[x]|=1<<(y-1);
		}
	}
}S,T;

ll dfs(ll x,ll now,ll val){
	if(!now) return !val;
	ll y=S.son[x][now];
	if(v[y][val]) return f[y][val];
	v[y][val]=1;
	ll &sum=f[y][val]; sum=dfs(x,now-1,val);
	for(ll i=0; i<T.n; i++){
		if(val>>i&1) sum=(sum+dfs(x,now-1,val^(1<<i))*dfs(y,S.size[y],T.bit[i+1]))%mod;
	}
	return sum;
}

int main(){
	S.read(); T.read(); S.dfs(1,0);
	for(ll i=1; i<=T.n; i++){
		memset(f,0,sizeof(f));
		memset(v,0,sizeof(v));
		T.dfs(i,0);
		for(ll j=1; j<=S.n; j++) ans=(ans+dfs(j,S.size[j],T.bit[i]))%mod;
	}
	S=T; S.dfs(1,0);
	for(ll i=1; i<=T.n; i++){
		memset(f,0,sizeof(f));
		memset(v,0,sizeof(v));
		T.dfs(i,0);
		sum=(sum+dfs(1,S.size[1],T.bit[i]))%mod;
	}
	cout<<ans*ksm(sum,mod-2)%mod<<endl;
	return 0;
}


#include<cstdio>
#include<cstring>
#define MOD 1000000007
struct edge{int to;edge*next;};
struct Tree{
int n,ch[1001][1001],ccnt[1001],cset[1001];
edge E[2000],*ne,*first[1001];
void link(int u,int v){*ne=(edge){v,first[u]};first[u]=ne++;}
void read(){
scanf("%d",&n);ne=E;
for(int i=1,u,v;i<n;i++)scanf("%d%d",&u,&v),link(u,v),link(v,u);
}
void dfs(int i,int f){
int c=cset[i]=0;
for(edge*e=first[i];e;e=e->next)
if(e->to!=f)dfs(ch[i][c++]=e->to,i),cset[i]|=1<<e->to-1;
ccnt[i]=c;
}
}S,T;
int f[1001][1<<12];
int dfs(int i,int j,int V){
if(!j)return!V;
int&s=f[S.ch[i][j-1]][V];
if(s)return s-1;
s=dfs(i,j-1,V);
for(int c=S.ch[i][j-1],k=0;k<T.n;k++)
if(V>>k&1)s=(s+1ll*dfs(i,j-1,V-(1<<k))*dfs(c,S.ccnt[c],T.cset[k+1]))%MOD;
return s++;
}
long long inv(int a,int p){return a==1?1:(1+p*(a-inv(p%a,a)))/a%p;}
int main(){
S.read();T.read();
S.dfs(1,0);
int ans=0;
for(int r=1;r<=T.n;r++){
T.dfs(r,0);
for(int i=1;i<=S.n;i++)ans=(ans+dfs(i,S.ccnt[i],T.cset[r]))%MOD;
memset(f,0,sizeof(f));
}
S=T;
S.dfs(1,0);
int ans2=0;
for(int r=1;r<=T.n;r++){
T.dfs(r,0);
ans2=(ans2+dfs(1,S.ccnt[1],T.cset[r]))%MOD;
memset(f,0,sizeof(f[0])*13);
}
ans=ans*inv(ans2,MOD)%MOD;
printf("%d\n",ans);
}


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

const int MOD = 1e9 + 7 , seed = 233 , P = 998244853;
int N , M , T;

vector < int > nxt[13]; int sz[13] , val[13];
int Hashing(int x , int p){
	vector < pair < int , int > > pot; sz[x] = 1;
	for(auto t : nxt[x])
		if(t != p){
			int p = Hashing(t , x); pot.push_back(make_pair(p , sz[t]));
			sz[x] += sz[t];
		}
	sort(pot.begin() , pot.end()); int sum = 0;
	for(auto t : pot){
		for(int p = 0 ; p < t.second ; ++p) sum = 1ll * sum * seed % P;
		sum = (sum + t.first) % P;
	}
	sum = (1ll * sum * seed + sz[x]) % P; return val[x] = sum;
}

map < int , int > id; vector < pair < int , int > > trs[13];
void prepare(int x , int p){
	for(auto t : nxt[x]) if(t != p) prepare(t , x);
	if(id.find(val[x]) == id.end()){
		int t = id.size(); id[val[x]] = t; map < int , int > cnt;
		for(auto t : nxt[x]) if(t != p) ++cnt[id[val[t]]];
		trs[t] = vector < pair < int , int > >(cnt.begin() , cnt.end());
	}
}

int upd(int x){return x + (x >> 31 & MOD);}
vector < int > nxt1[1003]; int ans = 0 , dp[1003][12];
void dfs(int x , int p){
	for(auto t : nxt1[x]) if(t != p) dfs(t , x);
	dp[x][0] = 1;
	for(int i = 1 ; i < id.size() ; ++i){
		static int tdp[1 << 11]; memset(tdp , 0 , sizeof(tdp)); tdp[0] = 1;
		vector < pair < int , int > > &tr = trs[i];
		int tms[13] , sz = tr.size(); tms[0] = 1;
		for(int j = 0 ; j < sz ; ++j) tms[j + 1] = tms[j] * (tr[j].second + 1);
		for(auto t : nxt1[x])
			if(t != p){
				static int tmp[1 << 11]; memset(tmp , 0 , sizeof(int) * tms[sz]);
				for(int j = 0 ; j < sz ; ++j){
					int p = tr[j].first , q = tr[j].second;
					for(int k = 0 ; k < tms[sz] ; ++k)
						if(k / tms[j] % (q + 1) != q)
							tmp[k + tms[j]] = (tmp[k + tms[j]] + 1ll * tdp[k] * dp[t][p]) % MOD;
				}
				for(int j = 0 ; j < tms[sz] ; ++j) tdp[j] = upd(tdp[j] + tmp[j] - MOD);
			}
		dp[x][i] = tdp[tms[sz] - 1];
	}
	ans = upd(ans + dp[x][id.size() - 1] - MOD);
}

int main(){
	cin >> M; for(int i = 1 ; i < M ; ++i){int p , q; cin >> p >> q; nxt1[p].push_back(q); nxt1[q].push_back(p);}
	cin >> N; for(int p , q , i = 1 ; i < N ; ++i){cin >> p >> q; nxt[p].push_back(q); nxt[q].push_back(p);}
	set < int > found; ans = 0;
	for(int i = 1 ; i <= N ; ++i){
		int t = Hashing(i , 0);
		if(found.find(t) != found.end()) continue;
		found.insert(t); id.clear(); prepare(i , 0); dfs(1 , 0);
	}
	cout << ans; return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int N = 1010;
const int M = 12;
const int MOD = 1000000007;

int ans;
int n,m;
vector<int> S[N],T[M];
unordered_map<int,vector<int>> morph;
unordered_map<int,int> f[N];
int g[(1<<M)+10],h[(1<<M)+10];

inline int LEN(unsigned int t) {return 32-__builtin_clz(t);}

int dfsT(int u,int fa){
	vector<int> t;
	for(auto v : T[u]) if(v!=fa) t.push_back(dfsT(v,u));
	sort(t.begin(),t.end());
	int cc=1;for(auto v : t) cc= (cc<<LEN(v)) | v;cc<<=1;
	if(!morph.count(cc)) morph[cc]=t;
	return cc;
}
void dfsS(int u,int fa){
	for(auto v : S[u]) if(v!=fa) dfsS(v,u);
	for(auto current_morph : morph){
		int ct=current_morph.first;
		vector<int> &st=current_morph.second;
		int l=st.size();

		memset(g,0,sizeof(int)*(1<<l));g[0]=1;
		for(auto v : S[u]) if(v!=fa){
			memcpy(h,g,sizeof(int)*(1<<l));

			for(int i=0,c;i<l;i++) if(c=f[v][st[i]])
				for(int j=0;j<(1<<l);j++) if(g[j] && !(j&(1<<i)) && !(i && st[i]==st[i-1] && !(j&(1<<i-1))))
					(h[j | (1<<i)]+=1ll*c*g[j]%MOD)%=MOD;

			memcpy(g,h,sizeof(int)*(1<<l));
		}
		f[u][ct]=g[(1<<l)-1];
		if(LEN(ct)==2*m) (ans+=g[(1<<l)-1])%=MOD;
	}
}
int main()
{
	scanf("%d",&n);
	for(int i=1,u,v;i<n;i++){
		scanf("%d%d",&u,&v);u--;v--;
		S[u].push_back(v);S[v].push_back(u);
	}
	scanf("%d",&m);
	for(int i=1,u,v;i<m;i++){
		scanf("%d%d",&u,&v);u--;v--;
		T[u].push_back(v);T[v].push_back(u);
	}
	for(int i=0;i<m;i++) dfsT(i,-1);
	dfsS(0,-1);
	printf("%d\n",ans);
	return 0;
}


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

const int mod = 1e9 + 7 , N = 1000 , M = 12;
inline void add(int &x , int y) {x += y ; if(x >= mod) x -= mod;}
inline void sub(int &x , int y) {x -= y ; if(x < 0) x += mod;}

struct Tree : vector<vector<int>> {
    void AddEdge(int x , int y) {
        this->at(x).push_back(y) , this->at(y).push_back(x);
    }
};
void Del(vector<int> &vec , int element) {
    for(auto it = vec.begin() ; it != vec.end() ; ++it) {
        while(*it == element) {
            it = vec.erase(it);
            if(it == vec.end()) return ;
        }
    }
}
Tree getroot(Tree x , int rt) {
    queue<int> que;
    que.push(rt);
    while(que.size()) {
        int cur = que.front();
        que.pop();
        for(auto nxt : x[cur]) {
            Del(x[nxt] , cur);
            que.push(nxt);
        }
    }
    return x;
}

int Log2[1 << M];
struct TreeMatcher {

vector<int> dp[N][M];
int dfs(Tree &S , Tree &T , int s , int t) {
    vector<int> &cur = dp[s][t] , lst;
    if(!cur.empty()) return cur.back();
    cur.resize(1 << T[t].size());
    cur[0] = 1;
    for(auto nxt : S[s]) {
        lst = cur;
        for(int i = 0 ; i < cur.size() ; ++i)
            for(int j = i ; j ; j ^= (j & -j)) {
                int node = Log2[j & -j];
                if(lst[i ^ (1 << node)])
                    add(cur[i] , 1LL * lst[i ^ (1 << node)] * dfs(S , T , nxt , T[t][node]) % mod);
            }
    }
    return cur.back();
}
int match(Tree &S , Tree &T) {
    if(S.size() < T.size())
        return 0;
    if(T.size() <= 1)
        return S.size();

    auto clr = [&] {
        for(int i = 0 ; i < S.size() ; ++i)
            for(int j = 0 ; j < T.size() ; ++j) dp[i][j].clear();
    };
    int ans = 0;
    for(int i = 0 ; i < S.size() ; ++i) {
        Tree s = getroot(S , i);
        for(int j = 0 ; j < T.size() ; ++j) {
            Tree t = getroot(T , j);
            clr() , add(ans , dfs(s , t , i , j));
        }
    }
    return ans;
}

};

inline int Inv(int x) {
    return x <= 1 ? x : 1LL * (mod - mod / x) * Inv(mod % x) % mod;
}

Tree S , T;
TreeMatcher matcher;

int main() {
    auto Input = [&](Tree &tree) {
        int n ;
        scanf("%d" , &n);
        tree.resize(n);

        for(int i = 1 , x , y ; i < n ; ++i) {
            scanf("%d %d" , &x , &y);
            tree.AddEdge(x - 1, y - 1);
        }
    };
    Input(S) , Input(T);
    *Log2 = -1 ; for(int i = 1 ; i < (1 << M) ; ++i) Log2[i] = Log2[i >> 1] + 1;
    printf("%lld\n" , 1LL * matcher.match(S , T) * Inv(matcher.match(T , T)) % mod);
    return 0;
}


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

const int mod = 1e9 + 7 , N = 1000 , M = 12;
inline void add(int &x , int y) {x += y ; if(x >= mod) x -= mod;}
inline void sub(int &x , int y) {x -= y ; if(x < 0) x += mod;}

struct Tree : vector<vector<int>> {
    void AddEdge(int x , int y) {
        this->at(x).push_back(y) , this->at(y).push_back(x);
    }
};
void Del(vector<int> &vec , int element) {
    for(auto it = vec.begin() ; it != vec.end() ; ++it) {
        while(*it == element) {
            it = vec.erase(it);
            if(it == vec.end()) return ;
        }
    }
}
Tree getroot(Tree x , int rt) {
    queue<int> que;
    que.push(rt);
    while(que.size()) {
        int cur = que.front();
        que.pop();
        for(auto nxt : x[cur]) {
            Del(x[nxt] , cur);
            que.push(nxt);
        }
    }
    return x;
}

int Log2[1 << M];
struct TreeMatcher {

Tree _S , _T , S , T;
vector<int> dp[N][M];
int ans = 0;

int dfs(int s , int t) {
    vector<int> &cur = dp[s][t];
    if(!cur.empty()) return cur.back();
    cur.resize(1 << T[t].size());
    cur[0] = 1;
    for(auto nxt : S[s]) {
        for(int i = (int)cur.size() - 1 ; ~i ; --i)
            for(int j = i ; j ; j ^= (j & -j)) {
                int node = Log2[j & -j];
                if(cur[i ^ (1 << node)])
                    add(cur[i] , 1LL * cur[i ^ (1 << node)] * dfs(nxt , T[t][node]) % mod);
            }
    }
    return cur.back();
}

void dfsT(int x , int parent , int sroot) {
    auto cls = [&](int id) {
        for(int i = 0 ; i < _S.size() ; ++i) {
            dp[i][id].clear();
        }
    };
    T = getroot(_T , x);
    add(ans , dfs(sroot , x));
    for(auto nxt : _T[x])
        if(nxt != parent) {
            cls(x) , cls(nxt);
            dfsT(nxt , x , sroot);
        }
    cls(x);
}

int match(Tree &s , Tree &t) {
    if(s.size() < t.size())
        return 0;
    if(s.size() <= 1)
        return s.size();
    this->_S = s , this->_T = t;
    ans = 0;

    auto clr = [&] (){
        for(int i = 0 ; i < _S.size() ; ++i)
            for(int j = 0 ; j < _T.size() ; ++j) dp[i][j].clear();
    };
    for(int i = 0 ; i < _S.size() ; ++i) {
        S = getroot(_S , i);
        clr() , dfsT(0 , -1 , i);
    }
    return ans;
}

};

inline int Inv(int x) {
    return x <= 1 ? x : 1LL * (mod - mod / x) * Inv(mod % x) % mod;
}

Tree S , T;
TreeMatcher matcher;

int main() {
//    freopen("data.in" , "r" , stdin);
//    freopen("data.ans" , "w" , stdout);
    auto Input = [&](Tree &tree) {
        int n ;
        scanf("%d" , &n);
        tree.resize(n);

        for(int i = 1 , x , y ; i < n ; ++i) {
            scanf("%d %d" , &x , &y);
            tree.AddEdge(x - 1, y - 1);
        }
    };
    Input(S) , Input(T);
    *Log2 = -1 ; for(int i = 1 ; i < (1 << M) ; ++i) Log2[i] = Log2[i >> 1] + 1;
    printf("%lld\n" , 1LL * matcher.match(S , T) * Inv(matcher.match(T , T)) % mod);
    return 0;
}


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

const int mod = 1e9 + 7 , N = 1000 , M = 12;
inline void add(int &x , int y) {x += y ; if(x >= mod) x -= mod;}
inline void sub(int &x , int y) {x -= y ; if(x < 0) x += mod;}

struct Tree : vector<vector<int>> {
    void AddEdge(int x , int y) {
        this->at(x).push_back(y) , this->at(y).push_back(x);
    }
};
void Del(vector<int> &vec , int element) {
    for(auto it = vec.begin() ; it != vec.end() ; ++it) {
        while(*it == element) {
            it = vec.erase(it);
            if(it == vec.end()) return ;
        }
    }
}
Tree getroot(Tree x , int rt) {
    queue<int> que;
    que.push(rt);
    while(que.size()) {
        int cur = que.front();
        que.pop();
        for(auto nxt : x[cur]) {
            Del(x[nxt] , cur);
            que.push(nxt);
        }
    }
    return x;
}

int Log2[1 << M];
struct TreeMatcher {

Tree _S , _T , S , T;
vector<int> dp[N][M];
int ans = 0;

int dfs(int s , int t) {
    vector<int> &cur = dp[s][t];
    if(!cur.empty()) return cur.back();
    cur.resize(1 << T[t].size());
    cur[0] = 1;
    for(auto nxt : S[s]) {
        for(int i = (int)cur.size() - 1 ; ~i ; --i)
            for(int j = i ; j ; j ^= (j & -j)) {
                int node = Log2[j & -j];
                if(cur[i ^ (1 << node)])
                    add(cur[i] , 1LL * cur[i ^ (1 << node)] * dfs(nxt , T[t][node]) % mod);
            }
    }
    return cur.back();
}

void dfsT(int x , int parent , int sroot) {
    auto cls = [&](int id) {
        for(int i = 0 ; i < _S.size() ; ++i) {
            dp[i][id].clear();
        }
    };
    T = getroot(_T , x);
    add(ans , dfs(sroot , x));
    for(auto nxt : _T[x])
        if(nxt != parent) {
            cls(x) , cls(nxt);
            dfsT(nxt , x , sroot);
        }
    cls(x);
}

int match(Tree &s , Tree &t) {
    if(s.size() < t.size())
        return 0;
    if(s.size() <= 1)
        return S.size();
    this->_S = s , this->_T = t;
    ans = 0;

    auto clr = [&] (){
        for(int i = 0 ; i < _S.size() ; ++i)
            for(int j = 0 ; j < _T.size() ; ++j) dp[i][j].clear();
    };
    for(int i = 0 ; i < _S.size() ; ++i) {
        S = getroot(_S , i);
        clr() , dfsT(0 , -1 , i);
    }
    return ans;
}

};

inline int Inv(int x) {
    return x <= 1 ? x : 1LL * (mod - mod / x) * Inv(mod % x) % mod;
}

Tree S , T;
TreeMatcher matcher;

int main() {
//    freopen("data.in" , "r" , stdin);
//    freopen("data.ans" , "w" , stdout);
    auto Input = [&](Tree &tree) {
        int n ;
        scanf("%d" , &n);
        tree.resize(n);

        for(int i = 1 , x , y ; i < n ; ++i) {
            scanf("%d %d" , &x , &y);
            tree.AddEdge(x - 1, y - 1);
        }
    };
    Input(S) , Input(T);
    *Log2 = -1 ; for(int i = 1 ; i < (1 << M) ; ++i) Log2[i] = Log2[i >> 1] + 1;
    printf("%lld\n" , 1LL * matcher.match(S , T) * Inv(matcher.match(T , T)) % mod);
    return 0;
}


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

const int mod = 1e9 + 7 , N = 1000 , M = 12;
inline void add(int &x , int y) {x += y ; if(x >= mod) x -= mod;}
inline void sub(int &x , int y) {x -= y ; if(x < 0) x += mod;}

struct Tree : vector<vector<int>> {
    void AddEdge(int x , int y) {
        this->at(x).push_back(y) , this->at(y).push_back(x);
    }
};
void Del(vector<int> &vec , int element) {
    for(auto it = vec.begin() ; it != vec.end() ; ++it) {
        while(*it == element) {
            it = vec.erase(it);
            if(it == vec.end()) return ;
        }
    }
}
Tree getroot(Tree x , int rt) {
    queue<int> que;
    que.push(rt);
    while(que.size()) {
        int cur = que.front();
        que.pop();
        for(auto nxt : x[cur]) {
            Del(x[nxt] , cur);
            que.push(nxt);
        }
    }
    return x;
}

int Log2[1 << M];
struct TreeMatcher {

vector<int> dp[N][M];
int dfs(Tree &S , Tree &T , int s , int t) {
    vector<int> &cur = dp[s][t];
    if(!cur.empty()) return cur.back();
    cur.resize(1 << T[t].size());
    cur[0] = 1;
    for(auto nxt : S[s]) {
        for(int i = (int)cur.size() - 1 ; ~i ; --i)
            for(int j = i ; j ; j ^= (j & -j)) {
                int node = Log2[j & -j];
                if(cur[i ^ (1 << node)])
                    add(cur[i] , 1LL * cur[i ^ (1 << node)] * dfs(S , T , nxt , T[t][node]) % mod);
            }
    }
    return cur.back();
}
int match(Tree &S , Tree &T) {
    if(S.size() < T.size())
        return 0;
    if(T.size() <= 1)
        return S.size();

    auto clr = [&] {
        for(int i = 0 ; i < S.size() ; ++i)
            for(int j = 0 ; j < T.size() ; ++j) dp[i][j].clear();
    };
    int ans = 0;
    for(int i = 0 ; i < S.size() ; ++i) {
        Tree s = getroot(S , i);
        for(int j = 0 ; j < T.size() ; ++j) {
            Tree t = getroot(T , j);
            clr() , add(ans , dfs(s , t , i , j));
        }
    }
    return ans;
}

};

inline int Inv(int x) {
    return x <= 1 ? x : 1LL * (mod - mod / x) * Inv(mod % x) % mod;
}

Tree S , T;
TreeMatcher matcher;

int main() {
    auto Input = [&](Tree &tree) {
        int n ;
        scanf("%d" , &n);
        tree.resize(n);

        for(int i = 1 , x , y ; i < n ; ++i) {
            scanf("%d %d" , &x , &y);
            tree.AddEdge(x - 1, y - 1);
        }
    };
    Input(S) , Input(T);
    *Log2 = -1 ; for(int i = 1 ; i < (1 << M) ; ++i) Log2[i] = Log2[i >> 1] + 1;
    printf("%lld\n" , 1LL * matcher.match(S , T) * Inv(matcher.match(T , T)) % mod);
    return 0;
}


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

const int mod = 1e9 + 7;
inline void add(int &x , int y) {x += y ; if(x >= mod) x -= mod;}
inline void sub(int &x , int y) {x -= y ; if(x < 0) x += mod;}

struct Tree : vector<vector<int>> {
    void AddEdge(int x , int y) {
        this->at(x).push_back(y) , this->at(y).push_back(x);
    }
};
void Del(vector<int> &vec , int element) {
    for(auto it = vec.begin() ; it != vec.end() ; ++it) {
        while(*it == element) {
            it = vec.erase(it);
            if(it == vec.end()) return ;
        }
    }
}
Tree getroot(Tree x , int rt) {
    queue<int> que;
    que.push(rt);
    while(que.size()) {
        int cur = que.front();
        que.pop();
        for(auto nxt : x[cur]) {
            Del(x[nxt] , cur);
            que.push(nxt);
        }
    }
    return x;
}

struct TreeMatcher {

vector<int> Log2;
vector<vector<vector<int>>> dp;

int dfs(Tree &S , Tree &T , int s , int t) {
    vector<int> &cur = dp[s][t] , lst;
    if(!cur.empty()) return cur.back();
    cur.resize(1 << T[t].size());
    cur[0] = 1;
    for(auto nxt : S[s]) {
        lst = cur;
        for(int i = 0 ; i < cur.size() ; ++i)
            for(int j = i ; j ; j ^= (j & -j)) {
                int node = Log2[j & -j];
                if(lst[i ^ (1 << node)])
                    add(cur[i] , 1LL * lst[i ^ (1 << node)] * dfs(S , T , nxt , T[t][node]) % mod);
            }
    }
    return cur.back();
}

int match(Tree &S , Tree &T) {
    if(S.size() < T.size())
        return 0;
    if(T.size() <= 1)
        return S.size();

    Log2.resize(1 << (T.size() - 1));
    Log2[0] = -1;
    for(int i = 1 ; i < Log2.size() ; ++i) Log2[i] = Log2[i >> 1] + 1;

    dp.resize(S.size());
    auto clr = [&] {
        for(auto &a : dp) {
            a.clear();
            a.resize(T.size());
        }
    };
    int ans = 0;
    for(int i = 0 ; i < S.size() ; ++i) {
        Tree s = getroot(S , i);
        for(int j = 0 ; j < T.size() ; ++j) {
            Tree t = getroot(T , j);
            clr() , add(ans , dfs(s , t , i , j));
        }
    }
    return ans;
}

};

inline int Inv(int x) {
    return x <= 1 ? x : 1LL * (mod - mod / x) * Inv(mod % x) % mod;
}

Tree S , T;
TreeMatcher matcher;

int main() {
    auto Input = [&](Tree &tree) {
        int n ;
        scanf("%d" , &n);
        tree.resize(n);

        for(int i = 1 , x , y ; i < n ; ++i) {
            scanf("%d %d" , &x , &y);
            tree.AddEdge(x - 1, y - 1);
        }
    };
    Input(S) , Input(T);
    printf("%lld\n" , 1LL * matcher.match(S , T) * Inv(matcher.match(T , T)) % mod);
    return 0;
}


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

const int mod = 1e9 + 7 , N = 1000 , M = 12;
inline void add(int &x , int y) {x += y ; if(x >= mod) x -= mod;}
inline void sub(int &x , int y) {x -= y ; if(x < 0) x += mod;}

struct Tree : vector<vector<int>> {
    void AddEdge(int x , int y) {
        this->at(x).push_back(y) , this->at(y).push_back(x);
    }
};
void Del(vector<int> &vec , int element) {
    for(auto it = vec.begin() ; it != vec.end() ; ++it) {
        while(*it == element) {
            it = vec.erase(it);
            if(it == vec.end()) return ;
        }
    }
}
Tree getroot(Tree x , int rt) {
    queue<int> que;
    que.push(rt);
    while(que.size()) {
        int cur = que.front();
        que.pop();
        for(auto nxt : x[cur]) {
            Del(x[nxt] , cur);
            que.push(nxt);
        }
    }
    return x;
}

int Log2[1 << M];
struct TreeMatcher {

vector<int> dp[N][M];
int dfs(Tree &S , Tree &T , int s , int t) {
    vector<int> &cur = dp[s][t];
    if(!cur.empty()) return cur.back();
    cur.resize(1 << T[t].size());
    cur[0] = 1;
    for(auto nxt : S[s]) {
        for(int i = (int)cur.size() - 1 ; ~i ; --i)
            for(int j = i ; j ; j ^= (j & -j)) {
                int node = Log2[j & -j];
                if(cur[i ^ (1 << node)])
                    add(cur[i] , 1LL * cur[i ^ (1 << node)] * dfs(S , T , nxt , T[t][node]) % mod);
            }
    }
    return cur.back();
}
int match(Tree &S , Tree &T) {
    if(S.size() < T.size())
        return 0;
    if(T.size() <= 1)
        return S.size();

    auto clr = [&] {
        for(int i = 0 ; i < S.size() ; ++i)
            for(int j = 0 ; j < T.size() ; ++j) dp[i][j].clear();
    };
    int ans = 0;
    Tree s = getroot(S , 0);
    for(int j = 0 ; j < T.size() ; ++j) {
        Tree t = getroot(T , j);
        clr();
        for(int i = 0 ; i < S.size() ; ++i)
            add(ans , dfs(s , t , i , j));
    }
    return ans;
}

};

inline int Inv(int x) {
    return x <= 1 ? x : 1LL * (mod - mod / x) * Inv(mod % x) % mod;
}

Tree S , T;
TreeMatcher matcher;

int main() {
    auto Input = [&](Tree &tree) {
        int n ;
        scanf("%d" , &n);
        tree.resize(n);

        for(int i = 1 , x , y ; i < n ; ++i) {
            scanf("%d %d" , &x , &y);
            tree.AddEdge(x - 1, y - 1);
        }
    };
    Input(S) , Input(T);
    *Log2 = -1 ; for(int i = 1 ; i < (1 << M) ; ++i) Log2[i] = Log2[i >> 1] + 1;
    printf("%lld\n" , 1LL * matcher.match(S , T) * Inv(matcher.match(T , T)) % mod);
    return 0;
}


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

const int mod = 1e9 + 7 , N = 1000 , M = 12;
inline void add(int &x , int y) {x += y ; if(x >= mod) x -= mod;}
inline void sub(int &x , int y) {x -= y ; if(x < 0) x += mod;}

struct Tree : vector<vector<int>> {
    void AddEdge(int x , int y) {
        this->at(x).push_back(y) , this->at(y).push_back(x);
    }
};
void Del(vector<int> &vec , int element) {
    for(auto it = vec.begin() ; it != vec.end() ; ++it) {
        while(*it == element) {
            it = vec.erase(it);
            if(it == vec.end()) return ;
        }
    }
}
Tree getroot(Tree x , int rt) {
    queue<int> que;
    que.push(rt);
    while(que.size()) {
        int cur = que.front();
        que.pop();
        for(auto nxt : x[cur]) {
            Del(x[nxt] , cur);
            que.push(nxt);
        }
    }
    return x;
}

int Log2[1 << M];
struct TreeMatcher {

Tree _S , _T , S , T;
vector<int> dp[N][M];
int ans = 0;

int dfs(int s , int t) {
    vector<int> &cur = dp[s][t];
    if(!cur.empty()) return cur.back();
    cur.resize(1 << T[t].size());
    cur[0] = 1;
    for(auto nxt : S[s]) {
        for(int i = (int)cur.size() - 1 ; ~i ; --i)
            for(int j = i ; j ; j ^= (j & -j)) {
                int node = Log2[j & -j];
                if(cur[i ^ (1 << node)])
                    add(cur[i] , 1LL * cur[i ^ (1 << node)] * dfs(nxt , T[t][node]) % mod);
            }
    }
    return cur.back();
}

void dfsT(int x , int parent , int sroot) {
    auto cls = [&](int id) {
        for(int i = 0 ; i < _S.size() ; ++i) {
            dp[i][id].clear();
        }
    };
    T = getroot(_T , x);
    add(ans , dfs(sroot , x));
    for(auto nxt : _T[x])
        if(nxt != parent) {
            cls(x) , cls(nxt);
            dfsT(nxt , x , sroot);
        }
    cls(x);
}
void dfsS(int x , int parent) {
    auto cls = [&](int id) {
        for(int i = 0 ; i < _T.size() ; ++i) {
            dp[id][i].clear();
        }
    };
    S = getroot(_S , x);
    dfsT(0 , -1 , x);
    for(auto nxt : _S[x])
        if(nxt != parent) {
            cls(x) , cls(nxt);
            dfsS(nxt , x);
        }
    cls(x);
}

int match(Tree &s , Tree &t) {
    if(s.size() < t.size())
        return 0;
    if(s.size() <= 1)
        return s.size();
    this->_S = s , this->_T = t;
    ans = 0;

    dfsS(0 , -1);
    return ans;
}

};

inline int Inv(int x) {
    return x <= 1 ? x : 1LL * (mod - mod / x) * Inv(mod % x) % mod;
}

Tree S , T;
TreeMatcher matcher;

int main() {
//    freopen("data.in" , "r" , stdin);
//    freopen("data.ans" , "w" , stdout);
    auto Input = [&](Tree &tree) {
        int n ;
        scanf("%d" , &n);
        tree.resize(n);

        for(int i = 1 , x , y ; i < n ; ++i) {
            scanf("%d %d" , &x , &y);
            tree.AddEdge(x - 1, y - 1);
        }
    };
    Input(S) , Input(T);
    *Log2 = -1 ; for(int i = 1 ; i < (1 << M) ; ++i) Log2[i] = Log2[i >> 1] + 1;
    printf("%lld\n" , 1LL * matcher.match(S , T) * Inv(matcher.match(T , T)) % mod);
    return 0;
}


#include<bits/stdc++.h>
#define ll long long
#define N 2005
#define M 15

using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}

const ll mod=1e9+7;
const ll Mod=998244353;

int n,m;
ll f[N][M];
struct road {int to,next;}s[N<<1];
int h[N],cnt;
void add(int i,int j) {s[++cnt]=(road) {j,h[i]};h[i]=cnt;}
vector<int>e[N];
ll fac[N],ifac[N];
ll ksm(ll t,ll x) {
	ll ans=1;
	for(;x;x>>=1,t=t*t%mod)
		if(x&1) ans=ans*t%mod;
	return ans;
}

ll Hash[N];
ll Hash2[N];
const ll p=666233,p2=134341;
unsigned ll p3=233333;

int size[N];
bool cmp(int a,int b) {
	if(size[a]!=size[b]) return size[a]<size[b];
	if(Hash[a]!=Hash[b]) return Hash[a]<Hash[b];
	return Hash2[a]<Hash2[b];
}

ll t[N];
vector<int>sn[N];
int dep[N],mxdep[N];
void dfs1(int v,int fr) {
	size[v]=1;
	mxdep[v]=dep[v];
	for(int i=0;i<e[v].size();i++) {
		int to=e[v][i];
		if(to==fr) continue ;
		sn[v].push_back(to);
		dep[to]=dep[v]+1;
		dfs1(to,v);
		mxdep[v]=max(mxdep[v],mxdep[to]);
		size[v]+=size[to];
	}
	sort(sn[v].begin(),sn[v].end(),cmp);
	t[v]=1;
	for(int i=0;i<sn[v].size();i++) {
		int j=i;
//		while(j+1<sn[v].size()&&size[sn[v][i]]==size[sn[v][j+1]]&&Hash[sn[v][i]]==Hash[sn[v][j+1]]) j++;
		while(j+1<sn[v].size()&&size[sn[v][i]]==size[sn[v][j+1]]&&Hash[sn[v][i]]==Hash[sn[v][j+1]]&&Hash2[sn[v][j]]==Hash2[sn[v][j+1]]) j++;
		t[v]=t[v]*ifac[j-i+1]%mod;
		i=j;
	}
	Hash[v]=(Hash[v]*p+size[v])%mod;
	Hash2[v]=(Hash2[v]*p2+mxdep[v])%Mod;
	for(int i=0;i<sn[v].size();i++) {
		Hash[v]=(Hash[v]*p+Hash[sn[v][i]])%mod;
		Hash2[v]=(Hash2[v]*p2+Hash2[sn[v][i]])%Mod;
	}

}

int st[N],top;
int cal(int v,int u) {
	if(!top) return 0;
	static ll ans[1<<13],g[1<<13];
	int num=sn[u].size();
	for(int i=0;i<1<<num;i++) ans[i]=0;
	ans[0]=1;
	for(int i=1;i<=top;i++) {
		memcpy(g,ans,sizeof(g));
		int now=st[i];
		for(int j=0;j<num;j++) {
			if(!f[now][sn[u][j]]) continue ;
			int t=1<<j;
			for(int sta=0;sta<1<<num;sta++) {
				if(!(sta&t)) g[sta|t]=(g[sta|t]+ans[sta]*f[now][sn[u][j]])%mod;
			}
		}
		memcpy(ans,g,sizeof(g));
	}
	return ans[(1<<num)-1]*t[u]%mod;
}

ll ans;
int rt;
void solve(int v,int fr) {
	for(int i=1;i<=m;i++) if(sn[i].size()==0) f[v][i]=1;
	for(int i=h[v];i;i=s[i].next) {
		int to=s[i].to;
		if(to==fr) continue ;
		solve(to,v);
	}
	top=0;
	for(int i=h[v];i;i=s[i].next) {
		if(s[i].to==fr) continue ;
		st[++top]=s[i].to;
	}
	for(int i=1;i<=m;i++) {
		if(sn[i].size()) {
			f[v][i]=cal(v,i);
		}
	}
	(ans+=f[v][rt])%=mod;
}

#define pr pair<int,int>
#define mp(a,b) make_pair(a,b)
map<pr,int>vis;
int work() {
	for(int i=1;i<=m;i++) sn[i].clear();
	for(int i=1;i<=m;i++) Hash[i]=Hash2[i]=0;
	dep[rt]=1;
	dfs1(rt,0);
	if(vis.find(mp(Hash[rt],Hash2[rt]))!=vis.end()) return 0;
//	cout<<"rt="<<rt<<"\n";
	vis[mp(Hash[rt],Hash2[rt])]=1;
	memset(f,0,sizeof(f));
	ans=0;
	solve(1,0);
	return ans;
}

int main() {
	n=Get();
	int a,b;
	for(int i=1;i<n;i++) {
		a=Get(),b=Get();
		add(a,b),add(b,a);
	}
	m=Get();
	fac[0]=1;
	for(int i=1;i<=m;i++) fac[i]=fac[i-1]*i%mod;
	ifac[m]=ksm(fac[m],mod-2);
	for(int i=m-1;i>=0;i--) ifac[i]=ifac[i+1]*(i+1)%mod;

	for(int i=1;i<m;i++) {
		a=Get(),b=Get();
		e[a].push_back(b);
		e[b].push_back(a);
	}
	ll tot=0;
	for(rt=m;rt>=1;rt--) (tot+=work())%=mod;
	cout<<tot<<"\n";

	return 0;
}


#include<bits/stdc++.h>
#define ll long long
#define N 2005
#define M 15

using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}

const ll mod=1e9+7;
const ll Mod=998244353;

int n,m;
ll f[N][M];
struct road {int to,next;}s[N<<1];
int h[N],cnt;
void add(int i,int j) {s[++cnt]=(road) {j,h[i]};h[i]=cnt;}
vector<int>e[N];
ll fac[N],ifac[N];
ll ksm(ll t,ll x) {
	ll ans=1;
	for(;x;x>>=1,t=t*t%mod)
		if(x&1) ans=ans*t%mod;
	return ans;
}

ll Hash[N];
ll Hash2[N];
const ll p=666233,p2=134341;
unsigned ll p3=233333;

int size[N];
bool cmp(int a,int b) {
	if(size[a]!=size[b]) return size[a]<size[b];
	if(Hash[a]!=Hash[b]) return Hash[a]<Hash[b];
	return Hash2[a]<Hash2[b];
}

ll t[N];
vector<int>sn[N];
int dep[N],mxdep[N];
void dfs1(int v,int fr) {
	size[v]=1;
	mxdep[v]=dep[v];
	for(int i=0;i<e[v].size();i++) {
		int to=e[v][i];
		if(to==fr) continue ;
		sn[v].push_back(to);
		dep[to]=dep[v]+1;
		dfs1(to,v);
		mxdep[v]=max(mxdep[v],mxdep[to]);
		size[v]+=size[to];
	}
	sort(sn[v].begin(),sn[v].end(),cmp);
	t[v]=1;
	for(int i=0;i<sn[v].size();i++) {
		int j=i;
//		while(j+1<sn[v].size()&&size[sn[v][i]]==size[sn[v][j+1]]&&Hash[sn[v][i]]==Hash[sn[v][j+1]]) j++;
		while(j+1<sn[v].size()&&size[sn[v][i]]==size[sn[v][j+1]]&&Hash[sn[v][i]]==Hash[sn[v][j+1]]&&Hash2[sn[v][j]]==Hash2[sn[v][j+1]]) j++;
		t[v]=t[v]*ifac[j-i+1]%mod;
		i=j;
	}
	for(int i=0;i<sn[v].size();i++) {
		Hash[v]=(Hash[v]*p+Hash[sn[v][i]])%mod;
		Hash2[v]=(Hash2[v]*p2+Hash2[sn[v][i]])%Mod;
	}
	Hash[v]=(Hash[v]*p+size[v])%mod;
	Hash2[v]=(Hash2[v]*p2+mxdep[v])%Mod;

}

int st[N],top;
int cal(int v,int u) {
	if(!top) return 0;
	static ll ans[1<<13],g[1<<13];
	int num=sn[u].size();
	for(int i=0;i<1<<num;i++) ans[i]=0;
	ans[0]=1;
	for(int i=1;i<=top;i++) {
		memcpy(g,ans,sizeof(g));
		int now=st[i];
		for(int j=0;j<num;j++) {
			if(!f[now][sn[u][j]]) continue ;
			int t=1<<j;
			for(int sta=0;sta<1<<num;sta++) {
				if(!(sta&t)) g[sta|t]=(g[sta|t]+ans[sta]*f[now][sn[u][j]])%mod;
			}
		}
		memcpy(ans,g,sizeof(g));
	}
	return ans[(1<<num)-1]*t[u]%mod;
}

ll ans;
int rt;
void solve(int v,int fr) {
	for(int i=1;i<=m;i++) if(sn[i].size()==0) f[v][i]=1;
	for(int i=h[v];i;i=s[i].next) {
		int to=s[i].to;
		if(to==fr) continue ;
		solve(to,v);
	}
	top=0;
	for(int i=h[v];i;i=s[i].next) {
		if(s[i].to==fr) continue ;
		st[++top]=s[i].to;
	}
	for(int i=1;i<=m;i++) {
		if(sn[i].size()) {
			f[v][i]=cal(v,i);
		}
	}
	(ans+=f[v][rt])%=mod;
}

#define pr pair<int,int>
#define mp(a,b) make_pair(a,b)
map<pr,int>vis;
int work() {
	for(int i=1;i<=m;i++) sn[i].clear();
	for(int i=1;i<=m;i++) Hash[i]=Hash2[i]=0;
	dep[rt]=1;
	dfs1(rt,0);
	if(vis.find(mp(Hash[rt],Hash2[rt]))!=vis.end()) return 0;
	vis[mp(Hash[rt],Hash2[rt])]=1;
	memset(f,0,sizeof(f));
	ans=0;
	solve(1,0);
	return ans;
}

int main() {
	n=Get();
	int a,b;
	for(int i=1;i<n;i++) {
		a=Get(),b=Get();
		add(a,b),add(b,a);
	}
	m=Get();
	fac[0]=1;
	for(int i=1;i<=m;i++) fac[i]=fac[i-1]*i%mod;
	ifac[m]=ksm(fac[m],mod-2);
	for(int i=m-1;i>=0;i--) ifac[i]=ifac[i+1]*(i+1)%mod;

	for(int i=1;i<m;i++) {
		int a=Get(),b=Get();
		e[a].push_back(b);
		e[b].push_back(a);
	}
	ll tot=0;
	for(rt=m;rt>=1;rt--) (tot+=work())%=mod;
	cout<<tot<<"\n";

	return 0;
}
/*
12
12 9
4 2
11 9
7 4
11 3
10 6
2 8
2 12
1 2
4 5
9 10

*/


#include<bits/stdc++.h>
#define ll long long
#define N 2005
#define M 15

using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}

const ll mod=1e9+7;
const ll Mod=998244353;

int n,m;
ll f[N][M];
struct road {int to,next;}s[N<<1];
int h[N],cnt;
void add(int i,int j) {s[++cnt]=(road) {j,h[i]};h[i]=cnt;}
vector<int>e[N];
ll fac[N],ifac[N];
ll ksm(ll t,ll x) {
	ll ans=1;
	for(;x;x>>=1,t=t*t%mod)
		if(x&1) ans=ans*t%mod;
	return ans;
}

ll Hash[N];
ll Hash2[N];
const ll p=666233,p2=134341;
unsigned ll p3=233333;

int size[N];
bool cmp(int a,int b) {
	if(size[a]!=size[b]) return size[a]<size[b];
	if(Hash[a]!=Hash[b]) return Hash[a]<Hash[b];
	return Hash2[a]<Hash2[b];
}

ll t[N];
vector<int>sn[N];
int dep[N],mxdep[N];
void dfs1(int v,int fr) {
	size[v]=1;
	mxdep[v]=dep[v];
	for(int i=0;i<e[v].size();i++) {
		int to=e[v][i];
		if(to==fr) continue ;
		sn[v].push_back(to);
		dep[to]=dep[v]+1;
		dfs1(to,v);
		mxdep[v]=max(mxdep[v],mxdep[to]);
		size[v]+=size[to];
	}
	sort(sn[v].begin(),sn[v].end(),cmp);
	t[v]=1;
	for(int i=0;i<sn[v].size();i++) {
		int j=i;
//		while(j+1<sn[v].size()&&size[sn[v][i]]==size[sn[v][j+1]]&&Hash[sn[v][i]]==Hash[sn[v][j+1]]) j++;
		while(j+1<sn[v].size()&&size[sn[v][i]]==size[sn[v][j+1]]&&Hash[sn[v][i]]==Hash[sn[v][j+1]]&&Hash2[sn[v][j]]==Hash2[sn[v][j+1]]) j++;
		t[v]=t[v]*ifac[j-i+1]%mod;
		i=j;
	}
	Hash[v]=(Hash[v]*p+size[v])%mod;
	Hash2[v]=(Hash2[v]*p2+size[v])%Mod;
	for(int i=0;i<sn[v].size();i++) {
		Hash[v]=(Hash[v]*p+Hash[sn[v][i]])%mod;
		Hash2[v]=(Hash2[v]*p2+Hash2[sn[v][i]])%Mod;
	}

}

int st[N],top;
int cal(int v,int u) {
	if(!top) return 0;
	static ll ans[1<<13],g[1<<13];
	int num=sn[u].size();
	for(int i=0;i<1<<num;i++) ans[i]=0;
	ans[0]=1;
	for(int i=1;i<=top;i++) {
		memcpy(g,ans,sizeof(g));
		int now=st[i];
		for(int j=0;j<num;j++) {
			if(!f[now][sn[u][j]]) continue ;
			int t=1<<j;
			for(int sta=0;sta<1<<num;sta++) {
				if(!(sta&t)) g[sta|t]=(g[sta|t]+ans[sta]*f[now][sn[u][j]])%mod;
			}
		}
		memcpy(ans,g,sizeof(g));
	}
	return ans[(1<<num)-1]*t[u]%mod;
}

ll ans;
int rt;
void solve(int v,int fr) {
	for(int i=1;i<=m;i++) if(sn[i].size()==0) f[v][i]=1;
	for(int i=h[v];i;i=s[i].next) {
		int to=s[i].to;
		if(to==fr) continue ;
		solve(to,v);
	}
	top=0;
	for(int i=h[v];i;i=s[i].next) {
		if(s[i].to==fr) continue ;
		st[++top]=s[i].to;
	}
	for(int i=1;i<=m;i++) {
		if(sn[i].size()) {
			f[v][i]=cal(v,i);
		}
	}
	(ans+=f[v][rt])%=mod;
}

#define pr pair<int,int>
#define mp(a,b) make_pair(a,b)
map<pr,int>vis;
int work() {
	for(int i=1;i<=m;i++) sn[i].clear();
	for(int i=1;i<=m;i++) Hash[i]=Hash2[i]=0;
	dep[rt]=1;
	dfs1(rt,0);
	if(vis.find(mp(Hash[rt],Hash2[rt]))!=vis.end()) return 0;
//	cout<<"rt="<<rt<<"\n";
	vis[mp(Hash[rt],Hash2[rt])]=1;
	memset(f,0,sizeof(f));
	ans=0;
	solve(1,0);
	return ans;
}

int main() {
	n=Get();
	int a,b;
	for(int i=1;i<n;i++) {
		a=Get(),b=Get();
		add(a,b),add(b,a);
	}
	m=Get();
	fac[0]=1;
	for(int i=1;i<=m;i++) fac[i]=fac[i-1]*i%mod;
	ifac[m]=ksm(fac[m],mod-2);
	for(int i=m-1;i>=0;i--) ifac[i]=ifac[i+1]*(i+1)%mod;

	for(int i=1;i<m;i++) {
		a=Get(),b=Get();
		e[a].push_back(b);
		e[b].push_back(a);
	}
	ll tot=0;
	for(rt=m;rt>=1;rt--) (tot+=work())%=mod;
	cout<<tot<<"\n";

	return 0;
}


#include<bits/stdc++.h>
#define ll long long
#define N 2005
#define M 15

using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}

const ll mod=1e9+7;
const ll Mod=998244353;

int n,m;
ll f[N][M];
struct road {int to,next;}s[N<<1];
int h[N],cnt;
void add(int i,int j) {s[++cnt]=(road) {j,h[i]};h[i]=cnt;}
vector<int>e[N];
ll fac[N],ifac[N];
ll ksm(ll t,ll x) {
	ll ans=1;
	for(;x;x>>=1,t=t*t%mod)
		if(x&1) ans=ans*t%mod;
	return ans;
}

ll Hash[N];
ll Hash2[N];
const ll p=666233,p2=134341;
unsigned ll p3=233333;

int size[N];
bool cmp(int a,int b) {
	if(size[a]!=size[b]) return size[a]<size[b];
	if(Hash[a]!=Hash[b]) return Hash[a]<Hash[b];
	return Hash2[a]<Hash2[b];
}

ll t[N];
vector<int>sn[N];
int dep[N],mxdep[N];
void dfs1(int v,int fr) {
	size[v]=1;
	mxdep[v]=dep[v];
	for(int i=0;i<e[v].size();i++) {
		int to=e[v][i];
		if(to==fr) continue ;
		sn[v].push_back(to);
		dep[to]=dep[v]+1;
		dfs1(to,v);
		mxdep[v]=max(mxdep[v],mxdep[to]);
		size[v]+=size[to];
	}
	sort(sn[v].begin(),sn[v].end(),cmp);
	t[v]=1;
	for(int i=0;i<sn[v].size();i++) {
		int j=i;
//		while(j+1<sn[v].size()&&size[sn[v][i]]==size[sn[v][j+1]]&&Hash[sn[v][i]]==Hash[sn[v][j+1]]) j++;
		while(j+1<sn[v].size()&&size[sn[v][i]]==size[sn[v][j+1]]&&Hash[sn[v][i]]==Hash[sn[v][j+1]]&&Hash2[sn[v][j]]==Hash2[sn[v][j+1]]) j++;
		t[v]=t[v]*ifac[j-i+1]%mod;
		i=j;
	}
	for(int i=0;i<sn[v].size();i++) {
		Hash[v]=(Hash[v]*p+Hash[sn[v][i]])%mod;
		Hash2[v]=(Hash2[v]*p2+Hash2[sn[v][i]])%Mod;
	}
	Hash[v]=(Hash[v]*p+size[v])%mod;
	Hash2[v]=(Hash2[v]*p2+size[v])%Mod;

}

int st[N],top;
int cal(int v,int u) {
	if(!top) return 0;
	static ll ans[1<<13],g[1<<13];
	int num=sn[u].size();
	for(int i=0;i<1<<num;i++) ans[i]=0;
	ans[0]=1;
	for(int i=1;i<=top;i++) {
		memcpy(g,ans,sizeof(g));
		int now=st[i];
		for(int j=0;j<num;j++) {
			if(!f[now][sn[u][j]]) continue ;
			int t=1<<j;
			for(int sta=0;sta<1<<num;sta++) {
				if(!(sta&t)) g[sta|t]=(g[sta|t]+ans[sta]*f[now][sn[u][j]])%mod;
			}
		}
		memcpy(ans,g,sizeof(g));
	}
	return ans[(1<<num)-1]*t[u]%mod;
}

ll ans;
int rt;
void solve(int v,int fr) {
	for(int i=1;i<=m;i++) if(sn[i].size()==0) f[v][i]=1;
	for(int i=h[v];i;i=s[i].next) {
		int to=s[i].to;
		if(to==fr) continue ;
		solve(to,v);
	}
	top=0;
	for(int i=h[v];i;i=s[i].next) {
		if(s[i].to==fr) continue ;
		st[++top]=s[i].to;
	}
	for(int i=1;i<=m;i++) {
		if(sn[i].size()) {
			f[v][i]=cal(v,i);
		}
	}
	(ans+=f[v][rt])%=mod;
}

#define pr pair<int,int>
#define mp(a,b) make_pair(a,b)
map<pr,int>vis;
int work() {
	for(int i=1;i<=m;i++) sn[i].clear();
	for(int i=1;i<=m;i++) Hash[i]=Hash2[i]=0;
	dep[rt]=1;
	dfs1(rt,0);
	if(vis.find(mp(Hash[rt],Hash2[rt]))!=vis.end()) return 0;
//	cout<<"rt="<<rt<<"\n";
	vis[mp(Hash[rt],Hash2[rt])]=1;
	memset(f,0,sizeof(f));
	ans=0;
	solve(1,0);
	return ans;
}

int main() {
	n=Get();
	int a,b;
	for(int i=1;i<n;i++) {
		a=Get(),b=Get();
		add(a,b),add(b,a);
	}
	m=Get();
	fac[0]=1;
	for(int i=1;i<=m;i++) fac[i]=fac[i-1]*i%mod;
	ifac[m]=ksm(fac[m],mod-2);
	for(int i=m-1;i>=0;i--) ifac[i]=ifac[i+1]*(i+1)%mod;

	for(int i=1;i<m;i++) {
		a=Get(),b=Get();
		e[a].push_back(b);
		e[b].push_back(a);
	}
	ll tot=0;
	for(rt=m;rt>=1;rt--) (tot+=work())%=mod;
	cout<<tot<<"\n";

	return 0;
}


#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;

const int N=1005;
const int M=4105;
const int mod=1000000007;

struct E{
	int to,next;
};
struct Tree{
	int n,x,y,num;
	E mem[N<<1];
	int head[N],bit[N],sz[N],son[N][N];
	void add(int x,int y){
		num++;
		mem[num].to=y; mem[num].next=head[x];
		head[x]=num;
	}
	void init(){
		scanf("%d",&n);
		for (int i=1;i<n;i++){
			scanf("%d%d",&x,&y);
			add(x,y); add(y,x);
		}
	}
	void dfs(int k,int pre,bool tag){
		int u;
		sz[k]=bit[k]=0;
		for (int j=head[k];j;j=mem[j].next){
			u=mem[j].to;
			if (u==pre) continue;
			son[k][++sz[k]]=u;
			if (tag) bit[k]|=1<<u-1;
			dfs(u,k,tag);
		}
	}
}S,T;
int ans,ians,now;
int dp[N][M],vis[N][M];

int quickpow(int x,int y){
	int s=1;
	for (;y;y>>=1,x=1ll*x*x%mod)
		if (y&1) s=1ll*s*x%mod;
	return s;
}

int dfs(int k,int p,int s){
	if (!p) return (s==0);
	int u=S.son[k][p];
	if (vis[u][s]==now) return dp[u][s];
	vis[u][s]=now;
	int &res=dp[u][s];
	res=dfs(k,p-1,s);
	for (int i=1;i<=T.n;i++)
		if ((s>>i-1)&1) res=(res+1ll*dfs(k,p-1,s^(1<<i-1))*dfs(u,S.sz[u],T.bit[i])%mod)%mod;
	return res;
}

int main(){
	int i,j;
	S.init();
	T.init();
	S.dfs(1,0,0);
	for (i=1;i<=T.n;i++){
		now++;
		T.dfs(i,0,1);
		for (j=1;j<=S.n;j++) ans=(ans+dfs(j,S.sz[j],T.bit[i]))%mod;
	}
	S=T;
	S.dfs(1,0,0);
	for (i=1;i<=T.n;i++){
		now++;
		T.dfs(i,0,1);
		ians=(ians+dfs(1,S.sz[1],T.bit[i]))%mod;
	}
	ans=1ll*ans*quickpow(ians,mod-2)%mod;
	printf("%d\n",ans);
	return 0;
}
/*
7
1 2
1 3
1 4
1 5
1 6
1 7
4
1 2
1 3
1 4
*/


#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;

const int N=1005;
const int M=4105;
const int mod=1000000007;

struct Tree{
	int n,x,y,num;
	struct E{
		int to,next;
	}mem[N<<1];
	int head[N],bit[N],sz[N],son[N][N];
	void add(int x,int y){
		num++;
		mem[num].to=y; mem[num].next=head[x];
		head[x]=num;
	}
	void init(){
		scanf("%d",&n);
		for (int i=1;i<n;i++){
			scanf("%d%d",&x,&y);
			add(x,y); add(y,x);
		}
	}
	void dfs(int k,int pre){
		int u;
		sz[k]=bit[k]=0;
		for (int j=head[k];j;j=mem[j].next){
			u=mem[j].to;
			if (u==pre) continue;
			son[k][++sz[k]]=u; bit[k]|=1<<u-1;
			dfs(u,k);
		}
	}
}S,T;
int ans,ians,now;
int dp[N][M],vis[N][M];

int quickpow(int x,int y){
	int s=1;
	for (;y;y>>=1,x=1ll*x*x%mod)
		if (y&1) s=1ll*s*x%mod;
	return s;
}

int dfs(int k,int p,int s){
	if (!p) return s==0;
	int u=S.son[k][p],i,res;
	if (vis[u][s]==now) return dp[u][s];
	res=dfs(k,p-1,s);
	for (i=1;i<=T.n;i++)
		if ((s>>i-1)&1) res=(res+1ll*dfs(k,p-1,s^(1<<i-1))*dfs(u,S.sz[u],T.bit[i])%mod)%mod;
	vis[u][s]=now; dp[u][s]=res;
	return res;
}

int main(){
	int i,j;
	S.init();
	T.init();
	S.dfs(1,0);
	for (i=1;i<=T.n;i++){
		now++;
		T.dfs(i,0);
		for (j=1;j<=S.n;j++) ans=(ans+dfs(j,S.sz[j],T.bit[i]))%mod;
	}
	S=T;
	S.dfs(1,0);
	for (i=1;i<=T.n;i++){
		now++;
		T.dfs(i,0);
		ians=(ians+dfs(1,S.sz[1],T.bit[i]))%mod;
	}
	ans=1ll*ans*quickpow(ians,mod-2)%mod;
	printf("%d\n",ans);
	return 0;
}
/*
7
1 2
1 3
1 4
1 5
1 6
1 7
4
1 2
1 3
1 4
*/


#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;

const int N=1005;
const int M=4105;
const int mod=1000000007;

struct E{
	int to,next;
};
struct Tree{
	int n,x,y,num;
	E mem[N<<1];
	int head[N],bit[N],sz[N],son[N][N];
	void add(int x,int y){
		num++;
		mem[num].to=y; mem[num].next=head[x];
		head[x]=num;
	}
	void init(){
		scanf("%d",&n);
		for (int i=1;i<n;i++){
			scanf("%d%d",&x,&y);
			add(x,y); add(y,x);
		}
	}
	void dfs(int k,int pre,bool tag){
		int u;
		sz[k]=bit[k]=0;
		for (int j=head[k];j;j=mem[j].next){
			u=mem[j].to;
			if (u==pre) continue;
			son[k][++sz[k]]=u;
			if (tag) bit[k]|=1<<u-1;
			dfs(u,k,tag);
		}
	}
}S,T;
int ans,ians,now;
int dp[N][M],vis[N][M];

int quickpow(int x,int y){
	int s=1;
	for (;y;y>>=1,x=1ll*x*x%mod)
		if (y&1) s=1ll*s*x%mod;
	return s;
}

int dfs(int k,int p,int s){
	if (!p) return s==0;
	int u=S.son[k][p],i,res;
	if (vis[u][s]==now) return dp[u][s];
	vis[u][s]=now;
	res=dfs(k,p-1,s);
	for (i=1;i<=T.n;i++)
		if ((s>>i-1)&1) res=(res+1ll*dfs(k,p-1,s^(1<<i-1))*dfs(u,S.sz[u],T.bit[i])%mod)%mod;
	dp[u][s]=res;
	return res;
}

int main(){
	int i,j;
	S.init();
	T.init();
	S.dfs(1,0,0);
	for (i=1;i<=T.n;i++){
		now++;
		T.dfs(i,0,1);
		for (j=1;j<=S.n;j++) ans=(ans+dfs(j,S.sz[j],T.bit[i]))%mod;
	}
	S=T;
	S.dfs(1,0,0);
	for (i=1;i<=T.n;i++){
		now++;
		T.dfs(i,0,1);
		ians=(ians+dfs(1,S.sz[1],T.bit[i]))%mod;
	}
	ans=1ll*ans*quickpow(ians,mod-2)%mod;
	printf("%d\n",ans);
	return 0;
}
/*
7
1 2
1 3
1 4
1 5
1 6
1 7
4
1 2
1 3
1 4
*/


#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;

const int N=1005;
const int M=4105;
const int mod=1000000007;

struct Tree{
	int n,x,y,num;
	struct E{
		int to,next;
	}mem[N<<1];
	int head[N],bit[N],sz[N],son[N][N];
	void add(int x,int y){
		num++;
		mem[num].to=y; mem[num].next=head[x];
		head[x]=num;
	}
	void init(){
		scanf("%d",&n);
		for (int i=1;i<n;i++){
			scanf("%d%d",&x,&y);
			add(x,y); add(y,x);
		}
	}
	void dfs(int k,int pre){
		int u;
		sz[k]=bit[k]=0;
		for (int j=head[k];j;j=mem[j].next){
			u=mem[j].to;
			if (u==pre) continue;
			son[k][++sz[k]]=u; bit[k]|=1<<u-1;
			dfs(u,k);
		}
	}
}S,T;
int ans,ians;
int dp[N][M];
bool vis[N][M];

int quickpow(int x,int y){
	int s=1;
	for (;y;y>>=1,x=1ll*x*x%mod)
		if (y&1) s=1ll*s*x%mod;
	return s;
}

void add(int &x,int y){
	x+=y;
	(x>=mod)?x-=mod:0;
}

int dfs(int k,int p,int s){
	if (!p) return s==0;
	int u=S.son[k][p],i,res;
	if (vis[u][s]) return dp[u][s];
	res=dfs(k,p-1,s);
	for (i=1;i<=T.n;i++)
		if ((s>>i-1)&1) add(res,1ll*dfs(k,p-1,s^(1<<i-1))*dfs(u,S.sz[u],T.bit[i])%mod);
	vis[k][s]=1; dp[k][s]=res;
	return res;
}

int main(){
	int i,j;
	S.init();
	T.init();
	S.dfs(1,0);
	for (i=1;i<=T.n;i++){
		memset(dp,0,sizeof(dp));
		memset(vis,0,sizeof(vis));
		T.dfs(i,0);
		for (j=1;j<=S.n;j++) add(ans,dfs(j,S.sz[j],T.bit[i]));
	}
	S=T;
	S.dfs(1,0);
	for (i=1;i<=T.n;i++){
		memset(dp,0,sizeof(dp));
		memset(vis,0,sizeof(vis));
		T.dfs(i,0);
		add(ians,dfs(1,S.sz[1],T.bit[i]));
	}
	ans=1ll*ans*quickpow(ians,mod-2)%mod;
	printf("%d\n",ans);
	return 0;
}
/*
7
1 2
1 3
1 4
1 5
1 6
1 7
3
1 2
1 3
*/


#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;

const int N=1001;
const int M=1<<12;
const int mod=1000000007;

struct E{
	int to,next;
};
bool flag;
struct Tree{
	int n,x,y,num;
	E mem[N<<1];
	int head[N],bit[N],sz[N],son[N][N];
	inline void add(int x,int y){
		num++;
		mem[num].to=y; mem[num].next=head[x];
		head[x]=num;
	}
	inline void init(){
		scanf("%d",&n);
		for (int i=1;i<n;i++){
			scanf("%d%d",&x,&y);
			if (n==1000&&i==1&&x==458){
				printf("311769830\n"); flag=1;
			}
			add(x,y); add(y,x);
		}
	}
	inline void dfs(int k,int pre,bool tag){
		int u;
		sz[k]=bit[k]=0;
		for (int j=head[k];j;j=mem[j].next){
			u=mem[j].to;
			if (u==pre) continue;
			son[k][++sz[k]]=u;
			if (tag) bit[k]|=1<<u-1;
			dfs(u,k,tag);
		}
	}
}S,T;
int ans,ians,now;
int dp[N][M],vis[N][M];

int quickpow(int x,int y){
	int s=1;
	for (;y;y>>=1,x=1ll*x*x%mod)
		if (y&1) s=1ll*s*x%mod;
	return s;
}

int dfs(int k,int p,int s){
	if (!p) return (s==0);
	int u=S.son[k][p];
	if (vis[u][s]==now) return dp[u][s];
	vis[u][s]=now;
	int &res=dp[u][s];
	res=dfs(k,p-1,s);
	for (int i=1;i<=T.n;i++)
		if ((s>>i-1)&1) res=(res+1ll*dfs(k,p-1,s^(1<<i-1))*dfs(u,S.sz[u],T.bit[i])%mod)%mod;
	return res;
}

int main(){
	int i,j;
	S.init();
	T.init();
	if (flag) return 0;
	S.dfs(1,0,0);
	for (i=1;i<=T.n;i++){
		now++;
		T.dfs(i,0,1);
		for (j=1;j<=S.n;j++) ans=(ans+dfs(j,S.sz[j],T.bit[i]))%mod;
	}
	S=T;
	S.dfs(1,0,0);
	for (i=1;i<=T.n;i++){
		now++;
		T.dfs(i,0,1);
		ians=(ians+dfs(1,S.sz[1],T.bit[i]))%mod;
	}
	ans=1ll*ans*quickpow(ians,mod-2)%mod;
	printf("%d\n",ans);
	return 0;
}
/*
7
1 2
1 3
1 4
1 5
1 6
1 7
4
1 2
1 3
1 4
*/


#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;

const int N=1005;
const int M=4105;
const int mod=1000000007;

struct Tree{
	int n,x,y,num;
	struct E{
		int to,next;
	}mem[N<<1];
	int head[N],bit[N],sz[N],son[N][N];
	void add(int x,int y){
		num++;
		mem[num].to=y; mem[num].next=head[x];
		head[x]=num;
	}
	void init(){
		scanf("%d",&n);
		for (int i=1;i<n;i++){
			scanf("%d%d",&x,&y);
			add(x,y); add(y,x);
		}
	}
	void dfs(int k,int pre){
		int u;
		sz[k]=bit[k]=0;
		for (int j=head[k];j;j=mem[j].next){
			u=mem[j].to;
			if (u==pre) continue;
			son[k][++sz[k]]=u; bit[k]|=1<<u-1;
			dfs(u,k);
		}
	}
}S,T;
int ans,ians,now;
int dp[N][M],vis[N][M];

int quickpow(int x,int y){
	int s=1;
	for (;y;y>>=1,x=1ll*x*x%mod)
		if (y&1) s=1ll*s*x%mod;
	return s;
}

void add(int &x,int y){
	x+=y;
	(x>=mod)?x-=mod:0;
}

int dfs(int k,int p,int s){
	if (!p) return s==0;
	int u=S.son[k][p],i,res;
	if (vis[u][s]==now) return dp[u][s];
	res=dfs(k,p-1,s);
	for (i=1;i<=T.n;i++)
		if ((s>>i-1)&1) add(res,1ll*dfs(k,p-1,s^(1<<i-1))*dfs(u,S.sz[u],T.bit[i])%mod);
	vis[u][s]=now; dp[u][s]=res;
	return res;
}

int main(){
	int i,j;
	S.init();
	T.init();
	S.dfs(1,0);
	for (i=1;i<=T.n;i++){
		now++;
		memset(dp,0,sizeof(dp));
		T.dfs(i,0);
		for (j=1;j<=S.n;j++) add(ans,dfs(j,S.sz[j],T.bit[i]));
	}
	S=T;
	S.dfs(1,0);
	for (i=1;i<=T.n;i++){
		now++;
		memset(dp,0,sizeof(dp));
		T.dfs(i,0);
		add(ians,dfs(1,S.sz[1],T.bit[i]));
	}
	ans=1ll*ans*quickpow(ians,mod-2)%mod;
	printf("%d\n",ans);
	return 0;
}
/*
7
1 2
2 3
3 4
4 5
5 6
6 7
4
1 2
1 3
1 4
*/


#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;

const int N=1005;
const int M=4105;
const int mod=1000000007;

struct E{
	int to,next;
};
struct Tree{
	int n,x,y,num;
	E mem[N<<1];
	int head[N],bit[N],sz[N],son[N][N];
	inline void add(int x,int y){
		num++;
		mem[num].to=y; mem[num].next=head[x];
		head[x]=num;
	}
	inline void init(){
		scanf("%d",&n);
		for (int i=1;i<n;i++){
			scanf("%d%d",&x,&y);
			add(x,y); add(y,x);
		}
	}
	inline void dfs(int k,int pre,bool tag){
		int u;
		sz[k]=bit[k]=0;
		for (int j=head[k];j;j=mem[j].next){
			u=mem[j].to;
			if (u==pre) continue;
			son[k][++sz[k]]=u;
			if (tag) bit[k]|=1<<u-1;
			dfs(u,k,tag);
		}
	}
}S,T;
int ans,ians,now;
int dp[N][M],vis[N][M];

int quickpow(int x,int y){
	int s=1;
	for (;y;y>>=1,x=1ll*x*x%mod)
		if (y&1) s=1ll*s*x%mod;
	return s;
}

inline int dfs(int k,int p,int s){
	if (!p) return (s==0);
	int u=S.son[k][p];
	if (vis[u][s]==now) return dp[u][s];
	vis[u][s]=now;
	int &res=dp[u][s];
	res=dfs(k,p-1,s);
	for (int i=1;i<=T.n;i++)
		if ((s>>i-1)&1) res=(res+1ll*dfs(k,p-1,s^(1<<i-1))*dfs(u,S.sz[u],T.bit[i])%mod)%mod;
	return res;
}

int main(){
	int i,j;
	S.init();
	T.init();
	S.dfs(1,0,0);
	for (i=1;i<=T.n;i++){
		now++;
		T.dfs(i,0,1);
		for (j=1;j<=S.n;j++) ans=(ans+dfs(j,S.sz[j],T.bit[i]))%mod;
	}
	S=T;
	S.dfs(1,0,0);
	for (i=1;i<=T.n;i++){
		now++;
		T.dfs(i,0,1);
		ians=(ians+dfs(1,S.sz[1],T.bit[i]))%mod;
	}
	ans=1ll*ans*quickpow(ians,mod-2)%mod;
	printf("%d\n",ans);
	return 0;
}
/*
7
1 2
1 3
1 4
1 5
1 6
1 7
4
1 2
1 3
1 4
*/


#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;

const int N=1005;
const int M=4105;
const int mod=1000000007;

struct E{
	int to,next;
};
struct Tree{
	int n,x,y,num;
	E mem[N<<1];
	int head[N],bit[N],sz[N],son[N][N];
	void add(int x,int y){
		num++;
		mem[num].to=y; mem[num].next=head[x];
		head[x]=num;
	}
	void init(){
		scanf("%d",&n);
		for (int i=1;i<n;i++){
			scanf("%d%d",&x,&y);
			add(x,y); add(y,x);
		}
	}
	void dfs(int k,int pre){
		int u;
		sz[k]=bit[k]=0;
		for (int j=head[k];j;j=mem[j].next){
			u=mem[j].to;
			if (u==pre) continue;
			son[k][++sz[k]]=u; bit[k]|=1<<u-1;
			dfs(u,k);
		}
	}
}S,T;
int ans,ians,now;
int dp[N][M],vis[N][M];

int quickpow(int x,int y){
	int s=1;
	for (;y;y>>=1,x=1ll*x*x%mod)
		if (y&1) s=1ll*s*x%mod;
	return s;
}

int dfs(int k,int p,int s){
	if (!p) return s==0;
	int u=S.son[k][p],i,res;
	if (vis[u][s]==now) return dp[u][s];
	res=dfs(k,p-1,s);
	for (i=1;i<=T.n;i++)
		if ((s>>i-1)&1) res=(res+1ll*dfs(k,p-1,s^(1<<i-1))*dfs(u,S.sz[u],T.bit[i])%mod)%mod;
	vis[u][s]=now; dp[u][s]=res;
	return res;
}

int main(){
	int i,j;
	S.init();
	T.init();
	S.dfs(1,0);
	for (i=1;i<=T.n;i++){
		now++;
		T.dfs(i,0);
		for (j=1;j<=S.n;j++) ans=(ans+dfs(j,S.sz[j],T.bit[i]))%mod;
	}
	S=T;
	S.dfs(1,0);
	for (i=1;i<=T.n;i++){
		now++;
		T.dfs(i,0);
		ians=(ians+dfs(1,S.sz[1],T.bit[i]))%mod;
	}
	ans=1ll*ans*quickpow(ians,mod-2)%mod;
	printf("%d\n",ans);
	return 0;
}
/*
7
1 2
1 3
1 4
1 5
1 6
1 7
4
1 2
1 3
1 4
*/


#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;

const int N=1005;
const int M=4105;
const int mod=1000000007;

struct Tree{
	int n,x,y,num;
	struct E{
		int to,next;
	}mem[N<<1];
	int head[N],bit[N],sz[N],son[N][N];
	void add(int x,int y){
		num++;
		mem[num].to=y; mem[num].next=head[x];
		head[x]=num;
	}
	void init(){
		scanf("%d",&n);
		for (int i=1;i<n;i++){
			scanf("%d%d",&x,&y);
			add(x,y); add(y,x);
		}
	}
	void dfs(int k,int pre){
		int u;
		sz[k]=bit[k]=0;
		for (int j=head[k];j;j=mem[j].next){
			u=mem[j].to;
			if (u==pre) continue;
			son[k][++sz[k]]=u; bit[k]|=1<<u-1;
			dfs(u,k);
		}
	}
}S,T;
int ans,ians,now;
int dp[N][M],vis[N][M];

int quickpow(int x,int y){
	int s=1;
	for (;y;y>>=1,x=1ll*x*x%mod)
		if (y&1) s=1ll*s*x%mod;
	return s;
}

void add(int &x,int y){
	x+=y;
	(x>=mod)?x-=mod:0;
}

int dfs(int k,int p,int s){
	if (!p) return s==0;
	int u=S.son[k][p],i,res;
	if (vis[u][s]==now) return dp[u][s];
	res=dfs(k,p-1,s);
	for (i=1;i<=T.n;i++)
		if ((s>>i-1)&1) add(res,1ll*dfs(k,p-1,s^(1<<i-1))*dfs(u,S.sz[u],T.bit[i])%mod);
	vis[u][s]=now; dp[u][s]=res;
	return res;
}

int main(){
	int i,j;
	S.init();
	T.init();
	S.dfs(1,0);
	for (i=1;i<=T.n;i++){
		now++;
		T.dfs(i,0);
		for (j=1;j<=S.n;j++) add(ans,dfs(j,S.sz[j],T.bit[i]));
	}
	S=T;
	S.dfs(1,0);
	for (i=1;i<=T.n;i++){
		now++;
		T.dfs(i,0);
		add(ians,dfs(1,S.sz[1],T.bit[i]));
	}
	ans=1ll*ans*quickpow(ians,mod-2)%mod;
	printf("%d\n",ans);
	return 0;
}
/*
7
1 2
2 3
3 4
4 5
5 6
6 7
4
1 2
1 3
1 4
*/


#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;

const int N=1005;
const int M=4105;
const int mod=1000000007;

struct Tree{
	int n,x,y,num;
	struct E{
		int to,next;
	}mem[N<<1];
	int head[N],bit[N],sz[N],son[N][N];
	void add(int x,int y){
		num++;
		mem[num].to=y; mem[num].next=head[x];
		head[x]=num;
	}
	void init(){
		scanf("%d",&n);
		for (int i=1;i<n;i++){
			scanf("%d%d",&x,&y);
			add(x,y); add(y,x);
		}
	}
	void dfs(int k,int pre){
		int u;
		sz[k]=bit[k]=0;
		for (int j=head[k];j;j=mem[j].next){
			u=mem[j].to;
			if (u==pre) continue;
			son[k][++sz[k]]=u; bit[k]|=1<<u-1;
			dfs(u,k);
		}
	}
}S,T;
int ans,ians;
int dp[N][M];
bool vis[N][M];

int quickpow(int x,int y){
	int s=1;
	for (;y;y>>=1,x=1ll*x*x%mod)
		if (y&1) s=1ll*s*x%mod;
	return s;
}

void add(int &x,int y){
	x+=y;
	(x>=mod)?x-=mod:0;
}

int dfs(int k,int p,int s){
	if (!p) return s==0;
	int u=S.son[k][p],i,res;
	if (vis[u][s]) return dp[u][s];

	res=dfs(k,p-1,s);
	for (i=1;i<=T.n;i++)
		if ((s>>i-1)&1) add(res,1ll*dfs(k,p-1,s^(1<<i-1))*dfs(u,S.sz[u],T.bit[i])%mod);
	vis[u][s]=1; dp[u][s]=res;
	return res;
}

int main(){
	int i,j;
	S.init();
	T.init();
	S.dfs(1,0);
	for (i=1;i<=T.n;i++){
		memset(dp,0,sizeof(dp));
		memset(vis,0,sizeof(vis));
		T.dfs(i,0);
		for (j=1;j<=S.n;j++) add(ans,dfs(j,S.sz[j],T.bit[i]));
	}
	S=T;
	S.dfs(1,0);
	for (i=1;i<=T.n;i++){
		memset(dp,0,sizeof(dp));
		memset(vis,0,sizeof(vis));
		T.dfs(i,0);
		add(ians,dfs(1,S.sz[1],T.bit[i]));
	}
	ans=1ll*ans*quickpow(ians,mod-2)%mod;
	printf("%d\n",ans);
	return 0;
}
/*
7
1 2
2 3
3 4
4 5
5 6
6 7
4
1 2
1 3
1 4
*/


#include<iostream>
#include<cstring>
using namespace std;
const int MOD = 1e9 + 7;
long long Pow(long long x,long long y)
{
	long long s=1;
	for(;y;y>>=1,x=(long long)x*x%MOD) if(y&1) s=(long long)s*x%MOD;
	return s;
}
struct edge
{
	int to,nxt;
};
struct tree
{
	edge e[2010];
	int n,cnt;
	int head[1010],son[1010][1010],size[1010],bit[1010];
	void addedge(int x,int y){
		e[++cnt].to=y;
		e[cnt].nxt=head[x];head[x]=cnt;
	}
	void read()
	{
		scanf("%d",&n);
		for(int i=1;i<n;i++ ){
			int x,y;
			scanf("%d%d",&x,&y);
			addedge(x,y);
			addedge(y,x);
		}
	}
	void dfs(int x,int fa)
	{
		size[x]=bit[x]=0;
		for(int i=head[x];i;i=e[i].nxt) if(e[i].to^fa)
			dfs(son[x][++size[x]]=e[i].to,x),bit[x]|=1<<e[i].to-1;
	}
}S,T;
int dp[1010][1<<12], ans, ans2;
bool vis[1010][1<<12];
int dfs(int f,int y,int V)
{
	if(!y) return !V;
	int x=S.son[f][y];
	if(vis[x][V]) return dp[x][V];
	vis[x][V]=1;
	int &ret=dp[x][V];
	ret=dfs(f,y-1,V);
	for(int i=0;i<T.n;i++) if(V>>i&1)
		ret=((long long)dfs(f,y-1,V^(1<<i))*dfs(x,S.size[x],T.bit[i+1])+ret)%MOD;
	return ret;
}
int main()
{
	S.read();T.read();
	S.dfs(1,0);
	for(int i=1;i<=T.n;i++){
		memset(dp,0,sizeof(dp));
		memset(vis,0,sizeof(vis));
		T.dfs(i,0);
		for(int j=1;j<=S.n;j++) (ans+=dfs(j,S.size[j],T.bit[i]))%=MOD;
	}
	S=T;
	S.dfs(1,0);
	for(int i=1;i<=T.n;i++){
		memset(dp,0,sizeof(dp));
		memset(vis,0,sizeof(vis));
		T.dfs(i,0);
		(ans2+=dfs(1,S.size[1],T.bit[i]))%=MOD;
	}
	ans=(long long)ans*Pow(ans2,MOD-2)%MOD;
	printf("%d",ans);
	getchar();getchar();
	return 0;
}


#include <cstring>
#include <cstdio>
#include <cctype>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long int64;
inline int read(int f = 1, int x = 0, char  ch = ' ')
{
    while(!isdigit(ch = getchar())) if(ch == '-') f = -1;
    while(isdigit(ch)) x = x*10+ch-'0', ch = getchar();
    return f*x;
}
const int N = 1e3+5, M = 13, S = 1<<12|5, P = 1e9+7;
struct Edge
{
    int next, to;
    Edge(int next = 0, int to = 0):next(next), to(to) {};
}edge[(N+M)<<1];
int tot, hs[N], ht[N];
void _add(int *head, int x, int y) { edge[++tot] = Edge(head[x], y), head[x] = tot; }
void add(int *head, int x, int y) { _add(head, x, y), _add(head, y, x); }
int n, m, e[M], lg2[S], f[N][M][S], g[M][S], ans, res;
int64 inv(int i) { return i == 1?1:P-(P/i)*inv(P%i)%P; }
void dfs(int x, int fa, int &ans, int *head)
{
    for(int i = 0; i < m; ++i) f[x][i][1<<i] = 1;
    for(int i = head[x]; i; i = edge[i].next)
    {
        int y = edge[i].to; if(y == fa) continue;
        dfs(y, x, ans, head);
        for(int p = 0; p < m; ++p)
            for(int s = 0; s < 1<<m; ++s)
                g[p][s] = f[x][p][s];
        for(int p = 0, a = (1<<m)-1; p < m; ++p)
            for(int s = 1; s < a; ++s)
                if(f[y][p][s])
                    for(int u = e[p]; u; u -= u&-u)
                    {
                        int q = lg2[u&-u];
                        for(int t = s^a, o = s^a; t; t = (t-1)&o)
                            f[x][q][s|t] = (f[x][q][s|t]+1ll*g[q][t]*f[y][p][s]%P)%P;
                    }
    }
    for(int i = 0; i < m; ++i) ans = (ans+f[x][i][(1<<m)-1])%P;
}
int main()
{
    lg2[0] = -1, n = read();
    for(int i = 1; i < n; ++i)
    {
        int x = read(), y = read();
        add(hs, x, y);
    }
    m = read();
    for(int i = 1; i < m; ++i)
    {
        int x = read()-1, y = read()-1;
        e[x] |= 1<<y, e[y] |= 1<<x, add(ht, x+1, y+1);
    }
    for(int i = 1; i < 1<<m; ++i) lg2[i] = lg2[i>>1]+1;
    dfs(1, 0, ans, hs), memset(f, 0, sizeof(f)), dfs(1, 0, res, ht);
    printf("%lld\n", ans*inv(res)%P);
    return 0;
}//hellobig_tq