// Slower C++ solution:
#include<cstdio>

#include<cstring>

#include<set>

#include<queue>

#include<algorithm>

using namespace std;

const int N=100005;

typedef pair<int,int> pi;

typedef set<int>::iterator sit;

int n,fa[N],cnt;

queue<pi> q;

set<int> G1[N],G2[N];

int find_father(int x){

	if(fa[x]==x)

        return x;

	return fa[x]=find_father(fa[x]);

}

int main()

{

	scanf("%d",&n);

	for(int i=1;i<=n;i++)

        fa[i]=i;

	for(int i=1;i<n;i++){

		int u,v;

		scanf("%d%d",&u,&v);

		G1[u].insert(v);

		G1[v].insert(u);

	}

	for(int i=1;i<n;i++){

		int u,v;

		scanf("%d%d",&u,&v);

		G2[u].insert(v);

		G2[v].insert(u);

		if(G1[u].find(v)!=G1[u].end())

            q.push(pi(u,v));

	}

	while(!q.empty()){

		int u=q.front().first,v=q.front().second;

		q.pop();

		u=find_father(u),v=find_father(v);

		if(u==v)

            continue;

		if(G1[u].size()+G2[u].size()>G1[v].size()+G2[v].size())

            swap(u,v);

		fa[u]=v;

		G1[u].erase(v);

		G1[v].erase(u);

		G2[u].erase(v);

		G2[v].erase(u);

		for(sit it=G1[u].begin();it!=G1[u].end();it++){

			int x=*it;

			G1[x].erase(u);

			G1[x].insert(v);

			G1[v].insert(x);

			if(G2[x].find(v)!=G2[x].end())

                q.push(pi(x,v));

		}

		for(sit it=G2[u].begin();it!=G2[u].end();it++){

			int x=*it;

			G2[x].erase(u);

			G2[x].insert(v);

			G2[v].insert(x);

			if(G1[x].find(v)!=G1[x].end())

                q.push(pi(x,v));

		}

	}

	int cnt=0;

	for(int i=1;i<=n;i++)

		if(find_father(i)==i)

            cnt++;

	puts(cnt==1?"YES":"NO");

}


// Faster C++ solution for the same problem (measured speedup: 1.8715082510710932x):
#include<bits/stdc++.h>

using namespace std;

#define rep(i, a, b) for(int i = (a), i##_end_ = (b); i <= i##_end_; ++i)

#define drep(i, a, b) for(int i = (a), i##_end_ = (b); i >= i##_end_; --i)

#define clar(a, b) memset((a), (b), sizeof(a))

#define debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;

typedef long double LD;

const double pi = acos(-1);

const int BUF_SIZE = (int)1e6 + 10;

template <typename T> inline bool chkmax(T &a, const T &b) {return a < b ? a = b, 1 : 0;}

template <typename T> inline bool chkmin(T &a, const T &b) {return a > b ? a = b, 1 : 0;}

LL read() {

	char ch = getchar();

	LL x = 0, flag = 1;

	for (;!isdigit(ch); ch = getchar()) if (ch == '-') flag *= -1;

	for (;isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;

	return x * flag;

}



const int Maxn = 1e5 + 9;

set <int> G[Maxn];

map<pair<int, int>, int> buc;

queue <pair<int, int> > que;

int fa[Maxn], n;

int find(int u) { return (fa[u] ^ u) ? (fa[u] = find(fa[u])) : u; }

void add(int u, int v) { G[u].insert(v); }



void link(int u, int v) {

	add(u, v), add(v, u);

	if (u > v) swap(u, v);

	if (++buc[make_pair(u, v)] == 2) que.push(make_pair(u, v));

}



void Init() {

	n = read();

	rep (i, 1, n) fa[i] = i;

	rep (i, 1, n - 1) link(read(), read());

	rep (i, 1, n - 1) link(read(), read());

}



void Solve() {

	int cnt = 0;

	while (!que.empty()) {

		pair<int, int> p = que.front(); que.pop(); 

		p.first = find(p.first), p.second = find(p.second);

		if (p.first == p.second) continue;



		int u = p.first, v = p.second;

		

		if (G[u].size() > G[v].size()) swap(u, v);

		++cnt, fa[u] = v;



		for (set <int> :: iterator IT = G[u].begin(); IT != G[u].end(); ++IT) {

			int q = find(*IT);

			if (q != v) link(q, v);

		}

	}

	printf("%s\n", cnt == n - 1 ? "YES" : "NO");

}



int main() {



	Init();

	Solve();



#ifdef Qrsikno

	debug("\nRunning time: %.3lf(s)\n", clock() * 1.0 / CLOCKS_PER_SEC);

#endif

	return 0;

}