#include <bits/stdc++.h>
inline void read(int& x) {
  x = 0;
  char c;
  while (!isdigit(c = getchar()))
    ;
  do x = x * 10 + c - '0';
  while (isdigit(c = getchar()));
}
inline void print(int x) {
  if (x < 10)
    putchar(x + '0');
  else
    print(x / 10), putchar(x % 10 + '0');
}
const int N = 1e5 + 5;
int n, m1, m2;
std::vector<std::pair<int, int>> ans;
struct union_find {
  int fa[N];
  inline void reset(int n) {
    for (int i = 1; i <= n; i++) fa[i] = i;
  }
  int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
  inline bool check(int u, int v) { return find(u) == find(v); }
  inline void merge(int u, int v) { fa[find(u)] = find(v); }
} s1, s2;
signed main() {
  read(n), read(m1), read(m2);
  s1.reset(n), s2.reset(n);
  for (int i = 1, u, v; i <= m1; i++) {
    read(u), read(v);
    s1.merge(u, v);
  }
  for (int i = 1, u, v; i <= m2; i++) {
    read(u), read(v);
    s2.merge(u, v);
  }
  for (int i = 2; i <= n; i++) {
    if (s1.check(i, 1) || s2.check(i, 1)) continue;
    s1.merge(i, 1), s2.merge(i, 1), ans.emplace_back(i, 1);
  }
  std::queue<int> ta, tb;
  for (int i = 2; i <= n; i++) {
    if (s1.check(1, i) && !s2.check(1, i)) ta.push(i);
    if (!s1.check(1, i) && s2.check(1, i)) tb.push(i);
  }
  while (true) {
    while (!ta.empty() && (!s1.check(1, ta.front()) || s2.check(1, ta.front())))
      ta.pop();
    while (!tb.empty() && (s1.check(1, tb.front()) || !s2.check(1, tb.front())))
      tb.pop();
    if (ta.empty() || tb.empty()) break;
    int x = ta.front(), y = tb.front();
    ta.pop(), tb.pop();
    ans.emplace_back(x, y);
    s1.merge(x, y), s2.merge(x, y);
  }
  print(ans.size()), putchar('\n');
  for (auto it : ans) {
    int x, y;
    std::tie(x, y) = it;
    print(x), putchar(' ');
    print(y), putchar('\n');
  }
  return 0;
}
