#include<bits/stdc++.h>
using namespace std;

#define int long long

#define rep(i,n) for(int i=0;i<(n);i++)
#define reps(i,a,b) for(int i=(a);i<(b);i++)
#define pb push_back
#define eb emplace_back
#define all(v) (v).begin(),(v).end()
#define fi first
#define se second

using vint=vector<int>;
using pint=pair<int,int>;
using vpint=vector<pint>;

template<typename A,typename B>inline void chmin(A &a,B b){if(a>b)a=b;}
template<typename A,typename B>inline void chmax(A &a,B b){if(a<b)a=b;}

template<class A,class B>
ostream& operator<<(ostream& ost,const pair<A,B>&p){
    ost<<"{"<<p.first<<","<<p.second<<"}";
    return ost;
}

template<class T>
ostream& operator<<(ostream& ost,const vector<T>&v){
    ost<<"{";
    for(int i=0;i<v.size();i++){
        if(i)ost<<",";
        ost<<v[i];
    }
    ost<<"}";
    return ost;
}

struct FastLCA{
    template<class T>
    struct SparseTable{
        vector<vector<T>>st;
        void init(const vector<T>&vec){
            int32_t b;
            for(b=0;(1<<b)<=vec.size();b++);
            st.assign(b,vector<T>(1<<b));
            for(int32_t i=0;i<vec.size();i++)st[0][i]=vec[i];

            for(int32_t i=1;i<b;i++){
                for(int32_t j=0;j+(1<<i)<=(1<<b);j++){
                    st[i][j]=min(st[i-1][j],st[i-1][j+(1<<(i-1))]);
                }
            }
        }
        T getMin(int32_t l,int32_t r){
            assert(l<r);
            int32_t b=32-__builtin_clz(r-l)-1;
            return min(st[b][l],st[b][r-(1<<b)]);
        }
    };
    SparseTable<pair<int32_t,int32_t>>st;

    vector<vector<int32_t>>G;
    int32_t V;
    int32_t root;
    vector<int32_t>ord;
    FastLCA(int32_t v=0,int32_t r=0):V(v),root(r),G(v),ord(v){}

    void set(int32_t v){
        *this=FastLCA(v);
    }

    void addEdge(int32_t a,int32_t b){
        G[a].push_back(b);
        G[b].push_back(a);
    }

    void dfs(int32_t v,int32_t p,int32_t d,vector<pair<int32_t,int32_t>>&vs){
        ord[v]=vs.size();
        vs.emplace_back(d,v);

        for(auto u:G[v]){
            if(u==p)continue;
            dfs(u,v,d+1,vs);
            vs.emplace_back(d,v);
        }
    }

    void init(){
        vector<pair<int32_t,int32_t>>vs;
        dfs(root,-1,0,vs);
        st.init(vs);
    }

    inline int32_t operator()(int32_t a,int32_t b){
        if(ord[a]>ord[b])swap(a,b);
        return st.getMin(ord[a],ord[b]+1).second;
    }
};
FastLCA lca;

template<class W>
struct WeightedTree{
    struct Edge{
        int to;
        W cost;
        Edge(int to,W cost):to(to),cost(cost){}
    };

    int V;
    int root;
    int E;
    vector<vector<Edge>>G;

    vector<int>par_,dep_,sz_,head_;
    vector<int>tin_,tout_,vs_;
    vector<W>dist_;
    WeightedTree(int V=0,int root=0):V(V),root(root),G(V),par_(V),sz_(V),dep_(V),head_(V),dist_(V),tin_(V),tout_(V),vs_(V),E(0){}
    void set(int v){
        *this=WeightedTree(v);
    }

    void addEdge(int a,int b,W c=W(1)){
        assert(a<V&&b<V);
        assert(E+1<V);
        G[a].push_back(Edge(b,c));
        G[b].push_back(Edge(a,c));
        E++;
    }

    void dfs(int v,int p,int d,W c){
        par_[v]=p;
        dep_[v]=d;
        sz_[v]=1;
        dist_[v]=c;

        for(auto &e:G[v]){
            if(e.to==p)continue;
            dfs(e.to,v,d+1,c+e.cost);
            sz_[v]+=sz_[e.to];
            if(G[v][0].to==p||sz_[e.to]>sz_[G[v][0].to])swap(G[v][0],e);
        }
    }

    void dfs_hld(int v,int &tt){
        vs_[tt]=v;
        tin_[v]=tt++;
        for(auto &e:G[v]){
            if(e.to==par_[v])continue;
            head_[e.to]=(e.to==G[v][0].to)?head_[v]:e.to;
            dfs_hld(e.to,tt);
        }
        tout_[v]=tt;
    }
    void init(){
        dfs(root,-1,0,W(0));
        int tt=0;
        dfs_hld(root,tt);
    }

    inline int lca(int u,int v)const{
        while(head_[u]!=head_[v]){
            if(dep_[head_[u]]<dep_[head_[v]])swap(u,v);
            u=par_[head_[u]];
        }
        return dep_[u]<dep_[v]?u:v;
    }

    
    inline int ancestor(int v,int k){
        while(v!=-1){
            if(dep_[v]-dep_[head_[v]]<k){
                k-=dep_[v]-dep_[head_[v]]+1;
                v=par_[head_[v]];
                continue;
            }
            return vs_[tin_[v]-k];
        }
        return -1;
    }
    

    inline int par(int v)const{
        return par_[v];
    }

    inline int size(int v)const{
        return sz_[v];
    }
    inline int len(int a,int b=0)const{
        int l=lca(a,b);
        return dep_[a]+dep_[b]-2*dep_[l];
    }
    inline W dist(int a,int b)const{
        int l=lca(a,b);
        return dist_[a]+dist_[b]-2*dist_[l];
    }

    inline W dist(int a)const{
        return dist_[a];
    }

    inline int dep(int v)const{
        return dep_[v];
    }
    inline int tin(int v)const{
        return tin_[v];
    }
    inline int tout(int v)const{
        return tout_[v];
    }

    inline int vs(int k)const{
        return vs_[k];
    }
    inline int heavy(int v)const{
        if(G[v].size()==0||G[v][0].to==par_[v])return -1;
        return G[v][0].to;
    }

    vector<Edge>& operator[](int i){
        return G[i];
    }
};
WeightedTree<int>T;

int N;
vint ord;
int cnt[2222];
vpint lis;
void solve(){
    vector<vint>bucket(N);
    rep(i,lis.size()){
        if(lis[i].fi==lis[i].se)continue;
        bucket[lis[i].fi].pb(i);
        bucket[lis[i].se].pb(i);
    }
    for(auto v:ord){
        if(v==0)return;

        if(bucket[v].size()==0)continue;
        if(bucket[v].size()==1){
            int k=bucket[v][0];
            if(lis[k].fi==v)lis[k].fi=T.par(v);
            else lis[k].se=T.par(v);
            solve();
            if(lis[k].fi==T.par(v))lis[k].fi=v;
            else lis[k].se=v;
            return;
        }

        int k=bucket[v][0];
        int l=bucket[v][1];
        if(lis[k].fi!=v)swap(lis[k].fi,lis[k].se);
        if(lis[l].fi!=v)swap(lis[l].fi,lis[l].se);
        int vk=lis[k].se;
        int vl=lis[l].se;
        lis[k]=pint(vk,vl);
        lis[l]=pint(-1,-1);
        for(int i=2;i<bucket[v].size();i++){
            int h=bucket[v][i];
            if(lis[h].fi!=v)swap(lis[h].fi,lis[h].se);
            lis[h].fi=T.par(v);    
        }
        solve();
        if(lis[k].fi==vk){
            lis[l].se=vl;
            lis[l].fi=v;
            lis[k].se=v;
        }
        else{
            lis[l].fi=vl;
            lis[l].se=v;
            lis[k].fi=v;
            lis[k].se=vk;
        }
        for(int i=2;i<bucket[v].size();i++){
            int h=bucket[v][i];
            if(lis[h].fi==T.par(v))lis[h].fi=v;
            else lis[h].se=v;
        }
        return;
    }
}

signed main(){
    int M;
    scanf("%lld%lld",&N,&M);
    lca.set(N);
    T.set(N);
    rep(i,N-1){
        int a,b;
        scanf("%lld%lld",&a,&b);
        a--;b--;
        lca.addEdge(a,b);
        T.addEdge(a,b);
    }

    lca.init();
    T.init();

    ord.resize(N);iota(all(ord),0);
    sort(all(ord),[&](int a,int b){
        if(T.dep(a)!=T.dep(b))return T.dep(a)>T.dep(b);
        return a<b;
    });



    rep(i,M){
        int a,b;
        scanf("%lld%lld",&a,&b);
        a--;b--;
        lis.eb(a,b);
    }

    vint cnt(N);
    rep(i,lis.size()){
        int u,v;
        tie(u,v)=lis[i];
        cnt[u]++;
        cnt[v]++;
        cnt[lca(u,v)]-=2;
    }
    for(int i=0;i+1<ord.size();i++)cnt[T.par(ord[i])]+=cnt[ord[i]];
    int ans=0;
    rep(i,N)ans+=min(cnt[i],2ll);

    solve();
    cout<<ans<<endl;
    for(auto p:lis)cout<<p.fi+1<<" "<<p.se+1<<endl;
    return 0;
}

Measured memory_bytes: 160256