#include <cstdio>
#include <vector>
#include <utility>

struct node_t
{
	std::vector<int> data;
	std::pair<int,int> answer;
	int lazy;
};

int n;
std::pair<int,int> saved_edges[100010];
bool removed[100010]; 
std::vector<int> edges[100010];
int size[100010],son[100010],top[100010],deep[100010],dfn[100010];
int father[100010];
struct node_t nodes[300030];
int qx,ql,qr;

void dfs0(int x,int y)
{
	int e;

	father[x] = y;
	deep[x] = deep[y] + 1;
	size[x] = 1;
	for(e = 0;e < edges[x].size();++e)
		if(edges[x][e] != y)
			dfs0(edges[x][e],x),size[x] += size[edges[x][e]],
				son[x] = (!son[x] || size[son[x]] < size[edges[x][e]]) ? edges[x][e] : son[x];
}

void dfs(int x,int y,int z)
{
	static int total = 1;
	int e;

	top[x] = z;
	dfn[x] = total++;
	if(son[x])
		dfs(son[x],x,z);
	for(e = 0;e < edges[x].size();++e)
		if(edges[x][e] != y && edges[x][e] != son[x])
			dfs(edges[x][e],x,edges[x][e]);
}

inline void node_update(int x)
{
	nodes[x].answer = std::min(nodes[x << 1].answer,nodes[(x << 1) | 1].answer);
}

inline void node_pushdown(int x)
{
	nodes[x << 1].lazy += nodes[x].lazy;
	nodes[(x << 1) | 1].lazy += nodes[x].lazy;
	nodes[(x << 1) | 1].answer.first += nodes[x].lazy;
	nodes[x << 1].answer.first += nodes[x].lazy;
	nodes[x].lazy = 0;
}

void tree_insert(int x,int l,int r)
{
	if(ql > r || qr < l)
		return;
	if(ql <= l && r <= qr){
		nodes[x].data.push_back(qx);
		++nodes[x].lazy;
		++nodes[x].answer.first;
		return;	
	}
	node_pushdown(x);
	tree_insert(x << 1,l,(l + r) >> 1);
	tree_insert((x << 1) | 1,((l + r) >> 1) + 1,r);
	node_update(x);
}

void tree_remove(int x,int l,int r)
{
	if(ql > r || qr < l)
		return;
	if(ql <= l && r <= qr){
		--nodes[x].lazy;
		--nodes[x].answer.first;
		return;	
	}
	node_pushdown(x);
	tree_remove(x << 1,l,(l + r) >> 1);
	tree_remove((x << 1) | 1,((l + r) >> 1) + 1,r);
	node_update(x);
}

int tree_get(int x,int l,int r)
{
	int k;

	for(k = 0;k < nodes[x].data.size();++k)
		if(!removed[nodes[x].data[k]])
			break;
	if(k != nodes[x].data.size())
		k = nodes[x].data[0] = nodes[x].data[k],nodes[x].data.resize(1);
	else
		nodes[x].data.clear(),k = 0;

	if(l == r){
		nodes[x].answer.first = 0x7f7f7f7f;
		return k;
	}

	node_pushdown(x);
	if(qx <= (l + r) >> 1)
		k += tree_get(x << 1,l,(l + r) >> 1);
	else
		k += tree_get((x << 1) | 1,((l + r) >> 1) + 1,r);
	node_update(x);
	return k;
}

void tree_build(int x,int l,int r)
{
	if(l == r){
		nodes[x].answer.second = l;
		return;
	}
	tree_build(x << 1,l,(l + r) >> 1);
	tree_build((x << 1) | 1,((l + r) >> 1) + 1,r);
	node_update(x);
}

int lca(int x,int y)
{
	while(top[x] != top[y])
		if(deep[top[x]] > deep[top[y]])
			x = father[top[x]];
		else
			y = father[top[y]];
	return deep[x] > deep[y] ? y : x;
}

void cover(int x,int y,bool z)
{
	while(top[x] != top[y])
		ql = dfn[top[x]],qr = dfn[x],tree_insert(1,2,n),x = father[top[x]];
	if(z || x != y)
		ql = dfn[y] + (z ? 0 : 1),qr = dfn[x],tree_insert(1,2,n);
}

void uncover(int x,int y,bool z)
{
	while(top[x] != top[y])
		ql = dfn[top[x]],qr = dfn[x],tree_remove(1,2,n),x = father[top[x]];
	if(z || x != y)
		ql = dfn[y] + (z ? 0 : 1),qr = dfn[x],tree_remove(1,2,n);
}

int main(void)
{
	int i;
	int u,v,w;

	//freopen("x.in","r",stdin);

	scanf("%d",&n);
	for(i = 1;i <= n - 1;++i)
		scanf("%d %d",&u,&v),edges[u].push_back(v),edges[v].push_back(u);

	dfs0(1,0);
	dfs(1,0,1);
	tree_build(1,2,n);

	for(i = 1;i <= n - 1;++i)
	{
		scanf("%d %d",&u,&v);
		saved_edges[i].first = u;
		saved_edges[i].second = v;
		qx = i;
		w = lca(u,v);
		cover(u,w,0);
		cover(v,w,0);
	}

	for(i = 1;i <= n - 1;++i)
	{
		if(nodes[1].answer.first != 1)
			return puts("NO"),0;
		qx = nodes[1].answer.second;
		w = tree_get(1,2,n);
		removed[w] = 1;
		u = saved_edges[w].first;
		v = saved_edges[w].second;
		w = lca(u,v);
		uncover(u,w,0);
		uncover(v,w,0);
	}
	puts("YES");

	return 0;
}

Measured memory_bytes: 38144