#include <bits/stdc++.h>
#include <atcoder/all>
using namespace std;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define rng(i,c,n) for(int i=c;i<n;i++)
#define fi first
#define se second
#define pb push_back
#define sz(a) (int) a.size()
#define all(a) a.begin(),a.end()
#define vec(...) vector<__VA_ARGS__>
#define _3zlqvu8 ios::sync_with_stdio(0),cin.tie(0)
typedef long long ll;
typedef vector<int> vi;
typedef pair<int,int> pii;
void print(){cout<<'\n';}
template<class h,class...t>
void print(const h&v,const t&...u){cout<<v<<' ',print(u...);}
#define nare cout<<"No\n"; exit(0);
#define yare cout<<"Yes\n";
struct treelca{
int n;
vi seg;
vec(vi) adj;
int timer;
vi tin,tout,tour,tourid,depth;
treelca(int m,int root,vec(vi) neadj){
init(m,root,neadj);
}
void init(int m,int root,vec(vi) neadj){
n=m;
timer=0;
tin=tout=tourid=depth=vi(n,0);
adj=neadj;
dfs(root,-1);
seg.resize(4*sz(tour));
build(1,0,sz(tour)-1);
}
void dfs(int v,int par){
tour.pb(v);
tourid[v]=sz(tour)-1;
tin[v]=timer++;
for(auto u:adj[v]){
if(u==par) continue;
depth[u]=depth[v]+1;
dfs(u,v);
tour.pb(v);
}
tout[v]=timer++;
}
void build(int node,int l,int r){
if(l==r){
seg[node]=tour[l];
}else{
int m=(l+r)>>1;
build(node*2,l,m);
build(node*2+1,m+1,r);
seg[node]=(tin[seg[node*2]]<tin[seg[node*2+1]]?
seg[node*2]:
seg[node*2+1]);
}
}
int query(int node,int l,int r,int _l,int _r){
if(l>_r or r<_l) return -1;
if(l>=_l and r<=_r) return seg[node];
int m=(l+r)>>1;
int vl=query(node*2,l,m,_l,_r),vr=query(node*2+1,m+1,r,_l,_r);
if(min(vl,vr)==-1) return max(vl,vr);
return (tin[vl]<tin[vr]?vl:vr);
}
int ancestor(int from,int to){
int tinfrom=tin[from],tinto=tin[to];
if(tinfrom>tinto) swap(tinfrom,tinto);
return query(1,0,sz(tour)-1,tinfrom,tinto);
}
int dist(int u,int v){
return depth[u]+depth[v]-depth[ancestor(u,v)]*2;
}
};
void slv(){
int n;
cin>>n;
vec(vi) adj(n);
rep(i,n-1){
int u,v;
cin>>u>>v;
u-=1,v-=1;
adj[u].pb(v),adj[v].pb(u);
}
vec(pii) a;
rep(i,n){
int s,e;
cin>>s>>e;
s-=1,e-=1;
a.pb({s,e});
}
vec(pii) to(n,{-1,-1});
vec(vec(pii)) adqry(n);
treelca lca(n,0,adj);
rep(i,n){
auto [s,e]=a[i];
int ho=0;
if(s>0 and e>0){
int up=lca.ancestor(s,e);
if(up==s or up==e){
if(lca.depth[s]>lca.depth[e]){
swap(s,e);
}
adqry[e].pb({lca.depth[s],i});
}else{
ho=1;
}
}else{
ho=1;
}
if(ho){
to[i]={s,e};
}
}
vi pns(n,-1);
vi par(n);
multiset<pii> mst;
auto dfs=[&](auto self,int v)->void{
int taken=0;
for(auto u:adj[v]){
if(u==par[v]) continue;
par[u]=v;
self(self,u);
if(v==0){
if(sz(mst)){
if(sz(mst)>1){
nare;
}
if(!taken){
pns[(*mst.begin()).se]=v;
taken=1;
mst.clear();
}else{
nare;
}
}
}
}
for(auto [d,x]:adqry[v]){
mst.insert({d,x});
}
if(v==0 and taken and sz(mst)){
nare;
}
if(sz(mst)){
auto it=prev(mst.end());
pii p=*it;
if(p.fi>lca.depth[v]){
nare;
}
pns[p.se]=v;
mst.erase(it);
}
};
dfs(dfs,0);
vi usd(n);
rep(v,n){
if(pns[v]!=-1){
usd[pns[v]]=1;
}
}
int si=0;
rep(v,n){
if(to[v].fi!=-1){
si+=1;
}
}
const int src=2*n;
const int sink=2*n+1;
atcoder::mf_graph<int> g(2*n+2);
rep(v,n){
auto [s,e]=to[v];
if(s!=-1){
g.add_edge(src,v,1);
g.add_edge(v,s+n,1);
g.add_edge(v,e+n,1);
}
}
rep(v,n){
if(!usd[v]){
g.add_edge(v+n,sink,1);
}
if(v){
g.add_edge(v+n,par[v]+n,1e9);
}
}
int cur=g.flow(src,sink);
if(cur!=si){
nare;
}
vec(vi) adqry1(n);
for(auto e:g.edges()){
if(e.flow==0) continue;
if(e.from<n){
int to=e.to-n;
adqry1[to].pb(e.from);
}
}
set<int> st;
auto rfs=[&](auto self,int v)->void{
for(auto u:adj[v]){
if(u==par[v]) continue;
self(self,u);
}
for(auto x:adqry1[v]){
st.insert(x);
}
if(sz(st)){
auto it=st.begin();
pns[*it]=v;
st.erase(it);
}
};
rfs(rfs,0);
rep(v,n){
cout<<pns[v]+1<<" ";
}
cout<<"\n";
}
signed main(){
_3zlqvu8;
slv();
}