#define DEB
#include<bits/stdc++.h>
#define REP(i,m) for(int i=0;i<(m);++i)
#define REPN(i,m,in) for(int i=(in);i<(m);++i)
#define ALL(t) (t).begin(),(t).end()
#define CLR(a) memset((a),0,sizeof(a))
#define pb push_back
#define mp make_pair
#define fr first
#define sc second

using namespace std;


#ifdef DEB
#define dump(x)  cerr << #x << " = " << (x) << endl
#define prl cerr<<"called:"<< __LINE__<<endl
#define dumpR(x) cerr<<"\x1b[31m"<<#x<<" = " <<(x)<<"\x1b[39m"<<endl
#define dumpY(x) cerr<<"\x1b[33m"<<#x<<" = " <<(x)<<"\x1b[39m"<<endl
#define dumpG(x) cerr<<"\x1b[32m"<<#x<<" = " <<(x)<<"\x1b[39m"<<endl
template<class T> void debug(T a,T b){ for(;a!=b;++a) cerr<<*a<<' ';cerr<<endl;}
#else
#define dump(x) ;
#define dumpR(x) ;
#define dumpY(x) ;
#define dumpG(x) ;
#define prl ;
template<class T> void debug(T a,T b){ ;}
#endif

template<class T> void chmin(T& a,const T& b) { if(a>b) a=b; }
template<class T> void chmax(T& a,const T& b) { if(a<b) a=b; }

typedef long long int lint;
typedef pair<int,int> pi;

namespace std{
  template<class S,class T>
  ostream &operator <<(ostream& out,const pair<S,T>& a){
    out<<'('<<a.fr<<','<<a.sc<<')';
    return out;
  }
}

//const int INF=5e8;

int n;
vector<int> g1[100005],g2[100005];
pi es1[100005],es2[100005];

struct uf{

  static const int MAXN=100005;
  int par[MAXN];
  int size[MAXN];
  void init(){
    memset(par,-1,sizeof(par));
    REP(i,MAXN) size[i]=1;
  }
  int root(int a){
    if(par[a]==-1) return a;
    return par[a]=root(par[a]);
  }
  void unite(int a,int b){
    a=root(a);b=root(b);
    if(a==b) return;
    par[b]=a;
    size[a]+=size[b];
  }
  bool same(int a,int b){
    return root(a)==root(b);
  }
};
uf u;

set<pi> q1[100005],q2[100005];//(to,id)
vector<pi> tocon;
void ins1(int a,int id,int to){
  q1[a].insert({to,id});
  auto it=q2[a].lower_bound({to,-1});
  if(it!=q2[a].end() && it->fr==to){
    tocon.pb({id,it->sc});
  }
}
void ins2(int a,int id,int to){
  q2[a].insert({to,id});
  auto it=q1[a].lower_bound({to,-1});
  if(it!=q1[a].end() && it->fr==to){
    tocon.pb({it->sc,id});
  }
}

void ers1(int i){
  int a=u.root(es1[i].fr),b=u.root(es1[i].sc);
  q1[a].erase({a,i});
  q1[b].erase({b,i});
}
void add1(int i){
  int a=u.root(es1[i].fr),b=u.root(es1[i].sc);
  if(a==b) return;
  ins1(a,i,b);
  ins1(b,i,a);
}
void ers2(int i){
  int a=u.root(es2[i].fr),b=u.root(es2[i].sc);
  q2[a].erase({a,i});
  q2[b].erase({b,i});
}
void add2(int i){
  int a=u.root(es2[i].fr),b=u.root(es2[i].sc);
  if(a==b) return;
  ins2(a,i,b);
  ins2(b,i,a);
}

bool done1[100005],done2[100005];
int main(){
  u.init();
  cin>>n;
  REP(i,n-1){
    int a,b;scanf("%d%d",&a,&b);--a;--b;
    es1[i]={a,b};
    add1(i);
    g1[a].pb(b);
    g1[b].pb(a);
  }
  REP(i,n-1){
    int a,b;scanf("%d%d",&a,&b);--a;--b;
    es2[i]={a,b};
    add2(i);
    g2[a].pb(b);
    g2[b].pb(a);
  }
  int cnt=0;
  while(!tocon.empty()){
    int A=tocon.back().fr,B=tocon.back().sc;
    tocon.pop_back();
    if(done1[A] && done2[B]) continue;
    if(done1[A] || done2[B]){
      assert(false);
    }
    done1[A]=1;done2[B]=1;
    int a=u.root(es1[A].fr),b=u.root(es1[A].sc);
    if(q1[a].size()+q2[a].size()<q1[b].size()+q2[b].size()) swap(a,b);
    vector<int> id1,id2;
    for(auto e:q1[b]){
      id1.pb(e.sc);
      ers1(e.sc);
    }
    for(auto e:q2[b]){
      id2.pb(e.sc);
      ers2(e.sc);
    }
    u.unite(a,b);
    for(auto e:id1) add1(e);
    for(auto e:id2) add2(e);
    ++cnt;
  }
  if(cnt==n-1) puts("YES");
  else puts("NO");
  return 0;
}





Measured memory_bytes: 61812