#include"testlib.h"
#include<bits/stdc++.h>
#define all(v) v.begin(), v.end()
 
using namespace std;
 
struct Dsu {
int n;
vector <int> par, cnt;
Dsu (int n_) {
    n = n_;
    par.resize(n + 1);
    cnt.resize(n + 1, 1);
    iota(all(par), 0);
}   
int root(int u) {
    if (par[u] == u) {
        return u;
    }
    else {
        return par[u] = root(par[u]);                
    }
}   
void mergefast(int u, int v) {
    if (cnt[v] < cnt[u]) {
        swap(u, v);
    }
    par[u] = v;
    cnt[v] += cnt[u];
}
bool merge(int u, int v) {
    u = root(u);
    v = root(v);
    if (u == v) {
        return 0;
    }
    if (cnt[v] < cnt[u]) {
        swap(u, v);
    }
    par[u] = v;
    cnt[v] += cnt[u];
    return 1;
}
};  
 
int32_t main(int argc, char *argv[]) {
    registerGen(argc, argv, 1);
    int T = opt<int>(1), N = opt<int>(2), M = opt<int>(3);
 
    cout << T << '\n';
    for (int t = 1; t <= T; ++t) {
    	int n = N;
    	int m = rnd.next(n - 1, (int)min((long long)n * (n - 1) / 2, (long long)M));
 
    	Dsu d(n);
    	set <pair <int, int> > edges;
    	while (edges.size() + 1 < n) {
    		int u = rnd.next(1, n), v = rnd.next(1, n);
    		if (v < u) {
    			swap(u, v);
    		}
    		if (d.root(u) != d.root(v)) {
    			edges.insert({u,v});
    			d.merge(u,v);
    		}
    	}
 
    	while (edges.size() < m) {
    		int u = rnd.next(1, n), v = rnd.next(1, n);
    		if (u == v) {
    			continue;
    		}
    		if (v < u) {
    			swap(u, v);
    		}
    		if (edges.find({u,v}) == edges.end()) {
    			edges.insert({u,v});
    		}
    	}
 
    	cout << n << ' ' << m << '\n';
    	for (auto [u, v] : edges) {
    		cout << u << ' ' << v << '\n';
    	}
    }
 
}
