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

const int N = 1 << 17;
const int INF = 1.01e9;

struct segtree {
    int n;
    vector<pair<int, int> > t1;
    vector<int> p1;

    vector<int> t2;
    vector<int> p2;

    segtree() {}
    void init(int _n) {
        n = _n;
        int N = 1;
        while (N < n) N <<= 1;
        N <<= 1;
        t1.resize(N);
        p1.resize(N);
        t2.resize(N);
        p2.resize(N);
        build(1, 0, n - 1);
    }

    void build(int v, int tl, int tr) {
        t2[v] = p2[v] = p1[v] = 0;
        if (tl == tr) {
            t1[v] = {0, tl};
            return;
        }
        int tm = (tl + tr) >> 1;
        build(v * 2, tl, tm);
        build(v * 2 + 1, tm + 1, tr);
        t1[v] = min(t1[v * 2], t1[v * 2 + 1]);
    }

    void push(int v, int tl, int tr) {
        if (p1[v]) {
            t1[v].first += p1[v];
            if (tl != tr) {
                p1[v * 2] += p1[v];
                p1[v * 2 + 1] += p1[v];
            }
            p1[v] = 0;
        }
        if (p2[v]) {
            t2[v] ^= p2[v];
            if (tl != tr) {
                p2[v * 2] ^= p2[v];
                p2[v * 2 + 1] ^= p2[v];
            }
            p2[v] = 0;
        }
    }

    void add(int v, int tl, int tr, int l, int r, int x) {
        push(v, tl, tr);
        if (l > r) return;
        if (l == tl && r == tr) {
            p1[v] = x;
            push(v, tl, tr);
            return;
        }
        int tm = (tl + tr) >> 1;
        add(v * 2, tl, tm, l, min(r, tm), x);
        add(v * 2 + 1, tm + 1, tr, max(l, tm + 1), r, x);
        t1[v] = min(t1[v * 2], t1[v * 2 + 1]);
        t2[v] = t2[v * 2] ^ t2[v * 2 + 1];
    }

    pair<int, int> get(int v, int tl, int tr, int l, int r) {
        push(v, tl, tr);
        if (l > r) return {INF, -1};
        if (l == tl && r == tr) return t1[v];
        int tm = (tl + tr) >> 1;
        return min(get(v * 2, tl, tm, l, min(r, tm)), get(v * 2 + 1, tm + 1, tr, max(l, tm + 1), r));
    }

    void upd(int v, int tl, int tr, int l, int r, int x) {
        push(v, tl, tr);
        if (l > r) return;
        if (l == tl && r == tr) {
            p2[v] = x;
            push(v, tl, tr);
            return;
        }
        int tm = (tl + tr) >> 1;
        upd(v * 2, tl, tm, l, min(r, tm), x);
        upd(v * 2 + 1, tm + 1, tr, max(l, tm + 1), r, x);
        t1[v] = min(t1[v * 2], t1[v * 2 + 1]);
        t2[v] = t2[v * 2] ^ t2[v * 2 + 1];
    }

    int get2(int v, int tl, int tr, int x) {
        push(v, tl, tr);
        if (tl == tr) return t2[v];
        int tm = (tl + tr) >> 1;
        if (x <= tm) return get2(v * 2, tl, tm, x);
        else return get2(v * 2 + 1, tm + 1, tr, x);
    }
};


int par[N], heavy[N], h[N];
int root[N], pos[N];
int n;
int vert[N];
vector<vector<int> > e;

segtree tree;

int dfs(int v) {
    int sz = 1, mx = 0;
    for (int to : e[v]) {
        if (to == par[v]) continue;
        par[to] = v;
        h[to] = h[v] + 1;
        int cur = dfs(to);
        if (cur > mx) heavy[v] = to, mx = cur;
        sz += cur;
    }
    return sz;
}

template <typename T>
void path(int u, int v, T op) {
    for (; root[u] != root[v]; v = par[root[v]]) {
        if (h[root[u]] > h[root[v]]) swap(u, v);
        op(pos[root[v]], pos[v]);
    }
    if (h[u] > h[v]) swap(u, v);
    op(pos[u] + 1, pos[v]);
}

void init(vector<vector<int> > _e) {
    e = _e;
    n = e.size();
    tree.init(n);
    memset(heavy, -1, sizeof(heavy[0]) * n);
    par[0] = -1;
    h[0] = 0;
    dfs(0);
    for (int i = 0, cpos = 0; i < n; i++) {
        if (par[i] == -1 || heavy[par[i]] != i) {
            for (int j = i; j != -1; j = heavy[j]) {
                root[j] = i;
                vert[cpos] = j;
                pos[j] = cpos++;
            }
        }
    }
}

/*void add(int v, int x) {
    tree.add(pos[v], x);
}*/

pair<int, int> getMin(int u, int v) {
    pair<int, int> res = {INF, -1};
    path(u, v, [&](int l, int r) {
        res = min(res, tree.get(1, 0, n - 1, l, r));
    });
    return res;
}

void add(int u, int v, int x) {
    path(u, v, [&](int l, int r) {
        tree.add(1, 0, n - 1, l, r, x);
    });
}

void xr(int u, int v, int x) {
    path(u, v, [&](int l, int r) {
        tree.upd(1, 0, n - 1, l, r, x);
    });
}

int get2(int v) {
    return tree.get2(1, 0, n - 1, pos[v]);
}

int main() {
#ifdef HOME
    assert(freopen("in", "r", stdin));
#endif

    int n;
    while (scanf("%d", &n) == 1) {
        vector<vector<int> > g(n);
        for (int i = 0; i < n - 1; i++) {
            int u, v;
            scanf("%d%d", &u, &v);
            --u; --v;
            g[u].push_back(v);
            g[v].push_back(u);
        }
        init(g);

        vector<int> u(n - 1), v(n - 1);
        for (int i = 0; i < n - 1; i++) {
            scanf("%d%d", &u[i], &v[i]);
            --u[i]; --v[i];
            add(u[i], v[i], 1);
            xr(u[i], v[i], i);
        }
        tree.add(1, 0, n - 1, pos[0], pos[0], INF);

        int cnt = 0;
        while (cnt < n - 1) {
            auto o = tree.get(1, 0, n - 1, 0, n - 1);
            if (o.first != 1) break;
            int cur = vert[o.second];
            int id = tree.get2(1, 0, n - 1, pos[cur]);
            add(v[id], u[id], -1);
            xr(v[id], u[id], id);
            add(cur, par[cur], INF);
            cnt++;
        }
        string ans = cnt == n - 1 ? "YES" : "NO";
        cout << ans << endl;
    }


#ifdef HOME
    cerr << "time: " << clock() * 1.0 / CLOCKS_PER_SEC << endl;
#endif
    return 0;
}

Measured memory_bytes: 31232