#include <bits/stdc++.h>
using namespace std;
const int N = 100000;
int n, m[2];
struct union_find_set {
  int uni[N + 9];
  void Build() {
    for (int i = 1; i <= n; ++i) uni[i] = i;
  }
  int Query_uni(int k) { return k == uni[k] ? k : uni[k] = Query_uni(uni[k]); }
  bool Merge(int x, int y) {
    x = Query_uni(x);
    y = Query_uni(y);
    if (x == y) return 0;
    uni[x] = y;
    return 1;
  }
  bool Query_con(int x, int y) { return Query_uni(x) == Query_uni(y); }
} a, b;
void into() {
  scanf("%d%d%d", &n, &m[0], &m[1]);
  a.Build();
  b.Build();
  for (int i = 1; i <= m[0]; ++i) {
    int x, y;
    scanf("%d%d", &x, &y);
    a.Merge(x, y);
  }
  for (int i = 1; i <= m[1]; ++i) {
    int x, y;
    scanf("%d%d", &x, &y);
    b.Merge(x, y);
  }
}
vector<pair<int, int> > ans;
void Get_ans() {
  for (int i = 1; i <= n; ++i)
    if (!a.Query_con(1, i) && !b.Query_con(1, i)) {
      a.Merge(1, i);
      b.Merge(1, i);
      ans.emplace_back(1, i);
    }
  vector<int> x, y;
  for (int i = 2; i <= n; ++i) {
    if (!a.Query_con(1, i) && a.Query_uni(i) == i) x.push_back(i);
    if (!b.Query_con(1, i) && b.Query_uni(i) == i) y.push_back(i);
  }
  for (int i = 0; i < x.size() && i < y.size(); ++i)
    ans.emplace_back(x[i], y[i]);
}
void work() { Get_ans(); }
void outo() {
  printf("%d\n", ans.size());
  for (auto [x, y] : ans) printf("%d %d\n", x, y);
}
int main() {
  int T = 1;
  for (; T--;) {
    into();
    work();
    outo();
  }
  return 0;
}
