const bool submit = 1;
#include <bits/stdc++.h>
#define rep(i,n) for(int i=0;i<(int)(n);i++)
#define rep1(i,n) for(int i=1;i<=(int)(n);i++)
#define all(c) c.begin(),c.end()
#define pb push_back
#define fs first
#define sc second
#define show(x) if(!submit) cout << #x << " = " << x << endl
#define chmin(x,y) x=min(x,y)
#define chmax(x,y) x=max(x,y)
using namespace std;
template<class S,class T> ostream& operator<<(ostream& o,const pair<S,T> &p){return o<<"("<<p.fs<<","<<p.sc<<")";}
template<class T> ostream& operator<<(ostream& o,const vector<T> &vc){o<<"sz = "<<vc.size()<<endl<<"[";for(const T& v:vc) o<<v<<",";o<<"]";return o;}

template<class Handler>
struct segtree_lazy{
	using val_t = typename Handler::val_t;
	using opr_t = typename Handler::opr_t;
	int N;
	vector<val_t> val;
	vector<opr_t> lazy;
	segtree_lazy(){}
	segtree_lazy(int n){init(n);}
	segtree_lazy(const vector<val_t>& vc){init(vc);}
	void init(int n){
		N=1;
		while(N<n) N*=2;
		val .assign(N*2,val_t::e());
		lazy.assign(N*2,opr_t::e());
	}
	void init(const vector<val_t>& vc){
		int n = vc.size();
		N=1;
		while(N<n) N*=2;
		val .assign(N*2,val_t::e());
		rep(i,n) val[i+N] = vc[i];
		for(int i=N-1;i>0;i--) val[i] = val[i*2] + val[i*2+1];
		lazy.assign(N*2,opr_t::e());
	}
	val_t realvalue(int k,int l,int r){
//		return Handler::act(lazy[k],val[k]);
		return Handler::act(lazy[k],val[k],k,l,r);
	}

	val_t query(int a,int b,int l=0,int r=-1,int k=1){	//query_calc
//		if(k==1) printf("query [%d,%d)\n",a,b);
		if(r==-1) r=N;
		if(b<=l||r<=a) return val_t::e();
		if(a<=l&&r<=b) return realvalue(k,l,r);
		propagate(l,r,k);
		val_t ret = query(a,b,l,(l+r)/2,k*2) + query(a,b,(l+r)/2,r,k*2+1);
		val[k] = realvalue(k*2,l,(l+r)/2) + realvalue(k*2+1,(l+r)/2,r);
		return ret;

	}
//	val_t query_leftassoc(){}
	void update(int a,int b,const opr_t &x,int l=0,int r=-1,int k=1){	//query_update
//		if(k==1) printf("update [%d,%d)\n",a,b);
		if(r==-1) r=N;
		if(b<=l||r<=a) return;
		if(a<=l&&r<=b){
			Handler::setg2fg(x,lazy[k]);
			return;
		}
		propagate(l,r,k);
		update(a,b,x,l,(l+r)/2,k*2);
		update(a,b,x,(l+r)/2,r,k*2+1);
		val[k] = realvalue(k*2,l,(l+r)/2) + realvalue(k*2+1,(l+r)/2,r);
	}
	void propagate(int l,int r,int k){	//opr_child -> opr_parent * opr_child		parent after child
		Handler::setg2fg(lazy[k],lazy[k*2  ]);
		Handler::setg2fg(lazy[k],lazy[k*2+1]);
		lazy[k] = opr_t::e();
	}
};

using P = pair<int,int>;

multiset<P> st;	//P(val,v)

template<class E, class Handler>		//for lazy segtree
struct HLdecomp{
	using val_t = typename Handler::val_t;
	using opr_t = typename Handler::opr_t;
	using segtree = segtree_lazy<Handler>;

	static const bool OnEdge = 1;

	vector<vector<E>> G;
	using P = pair<int,int>;
	vector<P> id;				//id[v] = P(chain_id,pos_on_chain)	posはtop to bottom
	vector<int> sz;				//sz[v] = subtree_size
	vector<int> dep;			//dep[v] = depth
	vector<int> par;			//par[v] = parent
	vector<int> top;			//id[v].fs の一番上

	int C;	//num of chains
	vector<vector<int>> chains;	//chains[c][i] = v <=> id[v] = P(c,i)
	vector<segtree> segs;


	HLdecomp(const vector<vector<E>>& G, int r = 0):G(G){
		int N = G.size();
		C = 1;
		chains.pb({0});
		id.assign(N,P(0,0));
		sz.assign(N,0);
		dep.assign(N,0);
		par.assign(N,0);
		top.assign(N,0);

		dfs_base(r);
		dfs_decomp(r);

	
		rep(c,C) segs.pb(segtree(chains[c].size()));
	}
	void dfs_base(int v,int p=-1){	//calc sz,dep
		sz[v] = 1;
		par[v] = p;
		if(p==-1) dep[v] = 0;
		else dep[v] = dep[p] + 1;
		for(const auto& e: G[v]){
			int u = e.to;
			if(u==p) continue;
			dfs_base(u,v);
			sz[v] += sz[u];
		}
	}
	void dfs_decomp(int v,int p=-1){
		int heavy = -1;
		for(const auto& e: G[v]){
			int u = e.to;
			if(u == p) continue;
			if(heavy == -1 || sz[heavy]<sz[u]) heavy = u;
		}
		for(const auto& e: G[v]){
			int u = e.to;
			if(u == p) continue;
			if(u == heavy){
				id[u] = P(id[v].fs,id[v].sc+1);
				top[u] = top[v];
			}else{
				id[u] = P(C,0);
				top[u] = u;
				C++;
				chains.pb({});
			}
			chains[id[u].fs].pb(u);
			dfs_decomp(u,v);
		}
	}
	int lca(int a,int b){
		while(id[a].fs != id[b].fs){
			if(id[a].fs < id[b].fs) b = par[top[b]];
			else a = par[top[a]];
		}
		return dep[a]<dep[b] ? a : b;
	}
	int up(int v,int d){	//vから上にd上がった点
		if(dep[v]<d) return -1;
		while(true){
			int d1 = dep[v] - dep[top[v]];
			if(d1<=d){
				d -= d1;
				v = top[v];
			}else{
				int c = id[v].fs;
				return chains[c][d1-d];
			}
			if(d==0) return v;
			v = par[v];
			d--;
		}
		assert(0);
		return -1;
	}
	val_t query(int u,int v){	//[u,w) + [w,v]			edge ver なら [u,w) + (w,v]
		int w = lca(u,v);
		val_t up,down;

		{
			for(;id[u].fs!=id[w].fs; u = par[top[u]]){
				//chains[c][l,r]
				int c = id[u].fs;
				int l = id[top[u]].sc;
				int r = id[u].sc;
				val_t x = segs[c].query(l,r+1);
				up = x + up;
			}
			int c = id[u].fs;
			int l = id[w].sc+1;
			int r = id[u].sc;
			val_t x = segs[c].query(l,r+1);
			up = x + up;
		}
		{
			u = v;
			for(;id[u].fs!=id[w].fs; u = par[top[u]]){
				int c = id[u].fs;
				int l = id[top[u]].sc;
				int r = id[u].sc;
				val_t x = segs[c].query(l,r+1);
				down = x + down;
			}
			int c = id[u].fs;
			int l = id[w].sc + OnEdge;
			int r = id[u].sc;
			val_t x = segs[c].query(l,r+1);
			down = x + down;
		}

		// ! reverse up !
		return up + down;
	}
	void update(int u,int v,const opr_t &x){	//[u,w) + [w,v]
		int w = lca(u,v);

		{
			for(;id[u].fs!=id[w].fs; u = par[top[u]]){
				//chains[c][l,r]
				int c = id[u].fs;
				int l = id[top[u]].sc;
				int r = id[u].sc;
				auto v = segs[c].query(0,chains[c].size());
				st.erase(P(v.x,v.id));
				segs[c].update(l,r+1,x);
				v = segs[c].query(0,chains[c].size());
				st.insert(P(v.x,v.id));
			}
			int c = id[u].fs;
			int l = id[w].sc+1;
			int r = id[u].sc;
			auto v = segs[c].query(0,chains[c].size());
			st.erase(P(v.x,v.id));
			segs[c].update(l,r+1,x);
			v = segs[c].query(0,chains[c].size());
			st.insert(P(v.x,v.id));
		}
		{
			u = v;
			for(;id[u].fs!=id[w].fs; u = par[top[u]]){
				int c = id[u].fs;
				int l = id[top[u]].sc;
				int r = id[u].sc;
				auto v = segs[c].query(0,chains[c].size());
				st.erase(P(v.x,v.id));
				segs[c].update(l,r+1,x);
				v = segs[c].query(0,chains[c].size());
				st.insert(P(v.x,v.id));
			}
			int c = id[u].fs;
			int l = id[w].sc + OnEdge;
			int r = id[u].sc;
			auto v = segs[c].query(0,chains[c].size());
			st.erase(P(v.x,v.id));
			segs[c].update(l,r+1,x);
			v = segs[c].query(0,chains[c].size());
			st.insert(P(v.x,v.id));
		}
	}
};

using ll = long long;
struct handler{
	struct val_t{
		ll x,y;
		int id;
		val_t(){*this = e();}
		val_t(ll x,ll y,int id):x(x),y(y),id(id){}

		const static val_t e(){
			return val_t(1e9,0,-1);
		}
		val_t operator+(const val_t &r) const {
			if(x<=r.x) return *this;
			else return r;
		}
		friend ostream& operator<<(ostream& o,const val_t& d){return o<<"("<<d.x<<" "<<d.y<<" "<<d.id<<")";}
	};

	struct opr_t{
		ll x,y;
		int id;
		opr_t(){*this = e();}
		opr_t(ll x,ll y):x(x),y(y),id(-1){}
		opr_t(ll x,ll y,int id):x(x),y(y),id(id){}

		const static opr_t e(){
			return opr_t(0,0,-1);
		}
	};

	static void setg2fg(const opr_t &f, opr_t &g){	//g -> fg		f after g
		g.x += f.x;
		g.y += f.y;
		if(f.id!=-1) g.id = f.id;
	}
	static val_t act(const opr_t &f, const val_t &v,int k,int l,int r){	//assign f.x -> sum = 
		return val_t(v.x+f.x,v.y+f.y,(f.id==-1?v.id:f.id));
	}
};

struct Edge{int to;};
int main(){
	using val_t = typename handler::val_t;
	using opr_t = typename handler::opr_t;

	int N;
	cin>>N;
	vector<vector<Edge>> G(N);
	rep(i,N-1){
		int x,y;
		cin>>x>>y;
		x--,y--;
		G[x].pb({y});
		G[y].pb({x});
	}
	using P = pair<int,int>;
	vector<P> vp;
	rep(i,N-1){
		int x,y;
		cin>>x>>y;
		x--,y--;
		vp.pb(P(x,y));
	}
	HLdecomp<Edge,handler> HLD(G);

	rep1(v,N-1){
		HLD.update(v,HLD.par[v],opr_t(-1e9,0,v));
	}

	rep(i,N-1){
		int x = vp[i].fs, y = vp[i].sc;
		HLD.update(x,y,opr_t(1,i));
	}

	for(P p:st){
		show(p);
	}
	rep1(i,N-1){
		val_t v = HLD.query(i,HLD.par[i]);
		show(v);
	}

	rep(ph,N-1){
		int cnt = st.begin()->fs, v = st.begin()->sc;
		show(cnt);
		show(v);

		if(cnt!=1){
			puts("NO");
			return 0;
		}
		int eid = HLD.query(v,HLD.par[v]).y;

		int x = vp[eid].fs, y = vp[eid].sc;
		HLD.update(x,y,opr_t(-1,-eid));
		HLD.update(v,HLD.par[v],opr_t(1e9,0));
	}
	puts("YES");

}


Measured memory_bytes: 40460