Twin Trees Bros.

To meet the demand of ICPC (International Cacao Plantation Consortium), you have to check whether two given trees are twins or not.

<image>
Example of two trees in the three-dimensional space.

The term tree in the graph theory means a connected graph where the number of edges is one less than the number of nodes. ICPC, in addition, gives three-dimensional grid points as the locations of the tree nodes. Their definition of two trees being twins is that, there exists a geometric transformation function which gives a one-to-one mapping of all the nodes of one tree to the nodes of the other such that for each edge of one tree, there exists an edge in the other tree connecting the corresponding nodes. The geometric transformation should be a combination of the following transformations:

* translations, in which coordinate values are added with some constants,
* uniform scaling with positive scale factors, in which all three coordinate values are multiplied by the same positive constant, and
* rotations of any amounts around either $x$-, $y$-, and $z$-axes.



Note that two trees can be twins in more than one way, that is, with different correspondences of nodes.

Write a program that decides whether two trees are twins or not and outputs the number of different node correspondences.

Hereinafter, transformations will be described in the right-handed $xyz$-coordinate system.

Trees in the sample inputs 1 through 4 are shown in the following figures. The numbers in the figures are the node numbers defined below.

<image>

For the sample input 1, each node of the red tree is mapped to the corresponding node of the blue tree by the transformation that translates $(-3, 0, 0)$, rotates $-\pi / 2$ around the $z$-axis, rotates $\pi / 4$ around the $x$-axis, and finally scales by $\sqrt{2}$. By this mapping, nodes #1, #2, and #3 of the red tree at $(0, 0, 0)$, $(1, 0, 0)$, and $(3, 0, 0)$ correspond to nodes #6, #5, and #4 of the blue tree at $(0, 3, 3)$, $(0, 2, 2)$, and $(0, 0, 0)$, respectively. This is the only possible correspondence of the twin trees.

For the sample input 2, red nodes #1, #2, #3, and #4 can be mapped to blue nodes #6, #5, #7, and #8. Another node correspondence exists that maps nodes #1, #2, #3, and #4 to #6, #5, #8, and #7.

For the sample input 3, the two trees are not twins. There exist transformations that map nodes of one tree to distinct nodes of the other, but the edge connections do not agree.

For the sample input 4, there is no transformation that maps nodes of one tree to those of the other.



Input

The input consists of a single test case of the following format.


$n$
$x_1$ $y_1$ $z_1$
.
.
.
$x_n$ $y_n$ $z_n$
$u_1$ $v_1$
.
.
.
$u_{n−1}$ $v_{n−1}$
$x_{n+1}$ $y_{n+1}$ $z_{n+1}$
.
.
.
$x_{2n}$ $y_{2n}$ $z_{2n}$
$u_n$ $v_n$
.
.
.
$u_{2n−2}$ $v_{2n−2}$


The input describes two trees. The first line contains an integer $n$ representing the number of nodes of each tree ($3 \leq n \leq 200$). Descriptions of two trees follow.

Description of a tree consists of $n$ lines that give the vertex positions and $n - 1$ lines that show the connection relation of the vertices.

Nodes are numbered $1$ through $n$ for the first tree, and $n + 1$ through $2n$ for the second tree.

The triplet $(x_i, y_i, z_i)$ gives the coordinates of the node numbered $i$. $x_i$, $y_i$, and $z_i$ are integers in the range between $-1000$ and $1000$, inclusive. Nodes of a single tree have distinct coordinates.

The pair of integers $(u_j , v_j )$ means that an edge exists between nodes numbered $u_j$ and $v_j$ ($u_j \ne v_j$). $1 \leq u_j \leq n$ and $1 \leq v_j \leq n$ hold for $1 \leq j \leq n - 1$, and $n + 1 \leq u_j \leq 2n$ and $n + 1 \leq v_j \leq 2n$ hold for $n \leq j \leq 2n - 2$.

Output

Output the number of different node correspondences if two trees are twins. Output a zero, otherwise.

Sample Input 1


3
0 0 0
1 0 0
3 0 0
1 2
2 3
0 0 0
0 2 2
0 3 3
4 5
5 6


Sample Output 1


1


Sample Input 2


4
1 0 0
2 0 0
2 1 0
2 -1 0
1 2
2 3
2 4
0 1 1
0 0 0
0 2 0
0 0 2
5 6
5 7
5 8


Sample Output 2


2


Example

Input

3
0 0 0
1 0 0
3 0 0
1 2
2 3
0 0 0
0 2 2
0 3 3
4 5
5 6


Output

1
#include <iostream>
#include <iomanip>
#include <vector>
#include <algorithm>
#include <cmath>
#include <map>
using namespace std;
const double EPS = 1e-8;
const double INF = 1e12;
const double PI = acos(-1);
#define EQ(n,m) (abs((n)-(m)) < EPS)

struct Point{
    double x,y,z;
    Point(double x, double y, double z):x(x), y(y), z(z){}
    Point(){}
    Point &operator +=(const Point &a){ x+=a.x; y+=a.y; z+=a.z; return *this; }
    Point &operator -=(const Point &a){ x-=a.x; y-=a.y; z-=a.z; return *this; }
    Point &operator *=(const double &a){ x*=a; y*=a; z*=a; return *this; }
    Point operator +(const Point &a) const{ return Point(x+a.x, y+a.y, z+a.z); }
    Point operator -(const Point &a) const{ return Point(x-a.x, y-a.y, z-a.z); }
    Point operator *(const double &a) const{ return Point(a*x, a*y, a*z); }
    Point operator -() { return Point(-x, -y, -z); }
};
double dot(const Point &a, const Point &b){
    return a.x*b.x +a.y*b.y +a.z*b.z;
}
Point cross(const Point &a, const Point &b){
    return Point(a.y*b.z -a.z*b.y, a.z*b.x -a.x*b.z, a.x*b.y -a.y*b.x);
}
double abs(const Point &a){
    return sqrt(dot(a, a));
}
Point unit(const Point &a){
    return a *(1/abs(a));
}
double arg2(const Point &a, const Point &b){
    return acos(dot(a, b)/(abs(a)*abs(b)));
}
bool operator ==(const Point &a, const Point &b){
    return abs(a-b) < EPS;
}
bool operator <(const Point &a, const Point &b){
    return !EQ(a.x,b.x)? a.x<b.x: !EQ(a.y,b.y)? a.y<b.y: a.z+EPS<b.z;
}
istream& operator>>(istream& is, Point& p){
    is >> p.x >> p.y >> p.z;
    return is;
}

Point rotate(const Point &p, const Point &axis, double angle){
    Point n = unit(axis);
    double SIN = sin(angle), COS = cos(angle);
    double vec[3] = {p.x, p.y, p.z};
    double mat[3][3] = {{COS +n.x*n.x*(1-COS), n.x*n.y*(1-COS) -n.z*SIN, n.x*n.z*(1-COS) +n.y*SIN},
                        {n.x*n.y*(1-COS) +n.z*SIN, COS +n.y*n.y*(1-COS), n.y*n.z*(1-COS) -n.x*SIN},
                        {n.x*n.z*(1-COS) -n.y*SIN, n.y*n.z*(1-COS) +n.x*SIN, COS +n.z*n.z*(1-COS)}};
    double ret[3] = {};
    for(int i=0; i<3; i++){
        for(int j=0; j<3; j++){
            ret[i] += mat[i][j] *vec[j];
        }
    }
    return Point(ret[0], ret[1], ret[2]);
}

vector<Point> trans(vector<Point> p, int ori, int axis){
    Point diff = p[ori];
    double mag = 1/(abs(p[ori]-p[axis]));
    for(auto &v: p){
        v = (v -diff) *mag;
    }
    if(!EQ(p[axis].x, 0) or !EQ(p[axis].y, 0)){
        Point dir = cross(p[axis], Point(0, 0, 1));
        double angle = arg2(p[axis], Point(0, 0, 1));
        for(auto &v: p){
            v = rotate(v, dir, angle);
        }
    }
    if(p[axis].z < 0){
        for(auto &v: p){
            v = rotate(v, Point(1, 0, 0), PI);
        }
    }
    return p;
}
bool spin(vector<Point> &p, int offc){
    if(EQ(p[offc].x, 0) and EQ(p[offc].y, 0)) return false;
    Point v=p[offc]; v.z=0;
    double angle = acos(dot(v, Point(1, 0, 0))/abs(v));
    if(p[offc].y > 0) angle = -angle;
    for(auto &v: p){
        v = rotate(v, Point(0, 0, 1), angle);
    }
    return true;
}
bool check(vector<Point> &v, map<Point, int> &crsp, vector<vector<vector<int>>> &adj){
    int n = adj[0].size();
    for(int i=0; i<n; i++){
        if(crsp.count(v[i]) == 0) return false;
    }
    for(int i=0; i<n; i++){
        vector<int> tmp;
        for(int next: adj[1][i]){
            tmp.push_back(crsp[v[next]]);
        }
        sort(tmp.begin(), tmp.end());
        if(tmp != adj[0][crsp[v[i]]]) return false;
    }
    return true;
}

int main(){
    int n;
    cin >> n;
    vector<vector<Point>> p(2, vector<Point>(n));
    vector<vector<vector<int>>> adj(2, vector<vector<int>>(n));
    for(int d=0; d<2; d++){
        for(int i=0; i<n; i++) cin >> p[d][i];
        for(int i=0; i<n-1; i++){
            int a,b;
            cin >> a >> b;
            a -= n*d +1;
            b -= n*d +1;
            adj[d][a].push_back(b);
            adj[d][b].push_back(a);
        }
    }
    for(int i=0; i<n; i++){
        sort(adj[0][i].begin(), adj[0][i].end());
    }

    int leaf;
    for(leaf=0; leaf<n; leaf++){
        if(adj[0][leaf].size() == 1) break;
    }
    p[0] = trans(p[0], leaf, adj[0][leaf][0]);
    int offc = leaf;
    for(int i=0; i<n; i++){
        if(spin(p[0], i)){
            offc = i;
            break;
        }
    }
    map<Point, int> crsp;
    for(int i=0; i<n; i++){
        crsp[p[0][i]] = i;
    }

    int ans = 0;
    for(int i=0; i<n; i++){
        if(adj[1][i].size() != 1) continue;
        vector<Point> v = trans(p[1], i, adj[1][i][0]);
        for(int j=0; j<n; j++){
            if(!EQ(p[0][offc].z, v[j].z)) continue;
            if(!EQ(abs(p[0][offc]), abs(v[j]))) continue;
            if(!spin(v, j)) continue;
            if(check(v, crsp, adj)) ans++;
        }
        if(offc==leaf and check(v, crsp, adj)){
            ans++;
        }
    }
    cout << ans << endl;
    return 0;
}
