#include <bits/stdc++.h>
using namespace std;
const int INF = (int)1e9 + 100;
const long long lINF = 1e18;
const double EPS = 1e-12;
int myrand() { return rand(); }
long long rdtsc() {
  long long ans;
  asm("rdtsc" : "=A"(ans));
  return ans;
}
int rnd(int x) { return myrand() % x; }
const int maxn = (int)5e5 + 100;
int n;
vector<pair<int, int> > edges[2];
vector<pair<int, int> > change[2];
int pr[maxn], mrank[maxn];
vector<pair<int *, int> > was;
void totime(int t) {
  while (((int)((was).size())) > t) {
    *(was.back().first) = was.back().second;
    was.pop_back();
  }
}
int getpar(int v) {
  if (pr[v] == v) {
    return v;
  } else {
    return getpar(pr[v]);
  }
}
void myUnion(int a, int b) {
  a = getpar(a);
  b = getpar(b);
  if (a == b) {
    return;
  }
  if (mrank[a] == mrank[b]) {
    was.emplace_back(mrank + a, mrank[a]);
    mrank[a]++;
  }
  if (mrank[a] < mrank[b]) {
    swap(a, b);
  }
  was.emplace_back(pr + b, pr[b]);
  pr[b] = a;
}
inline void myUnion(pair<int, int> ab) { myUnion(ab.first, ab.second); }
void precalc() {
  for (int i = 0; i < maxn; i++) {
    pr[i] = i;
    mrank[i] = 0;
  }
}
bool read() {
  if (scanf("%d", &n) < 1) {
    return false;
  }
  for (int it = 0; it < 2; it++) {
    edges[it] = vector<pair<int, int> >(n - 1);
    for (int i = 0; i < n - 1; i++) {
      scanf("%d%d", &edges[it][i].first, &edges[it][i].second);
      if (edges[it][i].first > edges[it][i].second) {
        swap(edges[it][i].first, edges[it][i].second);
      }
    }
  }
  return true;
}
bool solve(int vl, int vr) {
  if (vr > vl + 1) {
    int mid = (vl + vr) / 2;
    int t1 = ((int)((was).size()));
    for (int i = mid; i < vr; i++) {
      myUnion(change[0][i]);
    }
    int pos = vl;
    int t2 = ((int)((was).size()));
    for (int i = vl; pos < mid && i < vr; i++) {
      int a = change[1][i].first, b = change[1][i].second;
      a = getpar(a), b = getpar(b);
      if (a == b) {
        continue;
      }
      myUnion(a, b);
      swap(change[1][pos++], change[1][i]);
    }
    if (pos < mid) {
      return false;
    }
    totime(t2);
    if (!solve(vl, mid)) {
      return false;
    }
    totime(t1);
    for (int i = vl; i < mid; i++) {
      myUnion(change[1][i]);
    }
    if (!solve(mid, vr)) {
      return false;
    }
    totime(t1);
  }
  return true;
}
void solve() {
  for (int it = 0; it < 2; it++) {
    sort(edges[it].begin(), edges[it].end());
    change[!it].clear();
    for (int i = 0; i < n - 1; i++) {
      auto j = lower_bound(edges[it].begin(), edges[it].end(), edges[!it][i]);
      if (j == edges[it].end() || *j != edges[!it][i]) {
        change[!it].push_back(edges[!it][i]);
      } else if (it) {
        myUnion(edges[!it][i]);
      }
    }
  }
  bool ok = solve(0, ((int)((change[0]).size())));
  if (!ok) {
    assert(0);
    printf("-1\n");
  } else {
    printf("%d\n", ((int)((change[0]).size())));
    for (int i = 0; i < ((int)((change[0]).size())); i++) {
      printf("%d %d %d %d\n", change[0][i].first, change[0][i].second,
             change[1][i].first, change[1][i].second);
    }
  }
  totime(0);
}
int main() {
  srand(rdtsc());
  precalc();
  while (true) {
    if (!read()) {
      break;
    }
    solve();
    fprintf(stderr, "Time: %.18f\n", (double)clock() / CLOCKS_PER_SEC);
    fflush(stderr);
  }
  return 0;
}
