#include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <cctype>
#include <cfenv>
#include <cfloat>
#include <chrono>
#include <cinttypes>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdarg>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <deque>
#include <fstream>
#include <functional>
#include <immintrin.h>
#include <initializer_list>
#include <iomanip>
#include <ios>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <map>
#include <memory>
#include <new>
#include <numeric>
#include <ostream>
#include <queue>
#include <random>
#include <set>
#include <sstream>
#include <stack>
#include <streambuf>
#include <string>
#include <tuple>
#include <type_traits>
#include <variant>
using namespace std;
//numbers
using ll=long long;
#define int ll
using ld=long double;
//pairs
#define P pair
#define pi P<int,int>
#define ff first
#define ss second
#define mp make_pair
//std data structure
#define all(x) begin(x), end(x)
#define sz(x) (int) (x).size()
//vectors
#define V vector
#define vi V<int>
#define v2i V<vi>
#define v3i V<v2i>
#define vpi V<pi>
#define vsi V<si>
#define vb V<bool>
#define pb push_back
//sets
#define S set
#define MS multiset
#define US unordered_set
#define si S<int>
#define msi MS<int>
#define usi US<int>
#define ins insert
#define era erase
//maps
#define M map
#define UM unordered_map
#define mii M<int,int>
#define mivi UM<int,vi>
#define misi UM<int,si>
#define umii UM<int,int>
#define umivi UM<int,vi>
#define umisi UM<int,si>
//queues
#define Q queue
#define PQ priority_queue
#define qi Q<int>
#define qpi Q<pi>
#define pqi PQ<int>
#define rpqi PQ<int,vi,greater<int> >
#define pqpi PQ<pi>
#define rpqpi PQ<pi,vpi,greater<pi> >
//constants
const int MOD=998244353;
const int INF=922337203685477580;
using namespace std;
using ll = long long;
#define f(i,a,b) for(i=a;i<b;i++)
#define fi(i,a,b) for(i=a;i>=b;i--)
#define all(v) (v).begin(),(v).end()
#define vi(v) vector<int> v
#define vii(v) vector<ll> v
#define srt(v) sort(v, v + n)
#define no cout << "NO" << endl
#define yes cout << "YES" << endl
int i, j, z;
vector<vector<int> > vc;
vector<bool> vis;
vector<vector<int> > tree;
vector<pair<int, pair<int, int> > > pairs;
set<int> have;
map<int, set<int> > done;
void dfs(int u, int p) {
if(have.find(u) != have.end())
have.erase(have.find(u));
else
return;
for(auto x : vc[u]) {
if(have.find(x) == have.end())
continue;
if(x == p)
continue;
tree[x].push_back(u);
tree[u].push_back(x);
dfs(x, u);
}
return;
}
bool tre(int u, int p, int alw) {
if(tree[u].size() == 1 && u != alw)
return false;
set<int> st;
for(auto x : vc[u]) {
if(x != p && done[x].find(u) == done[x].end()) {
st.insert(x);
done[x].insert(u);
done[u].insert(x);
}
}
set<int> realst;
for(auto x : tree[u]) {
if(x == p)
continue;
bool get = tre(x, u, alw);
if(get) {
st.erase(st.find(x));
}
}
if(st.size() % 2) {
if(p != 0)
st.insert(p);
int sz = st.size();
vector<int> copy;
for(auto x : st)
copy.push_back(x);
for(i = 0; i < sz - 1; i += 2) {
pairs.push_back({u, {copy[i], copy[i + 1]}});
}
return true;
}
else {
int sz = st.size();
vector<int> copy;
for(auto x : st)
copy.push_back(x);
for(i = 0; i < sz - 1; i += 2) {
pairs.push_back({u, {copy[i], copy[i + 1]}});
}
return false;
}
}
void solve() {
pairs.clear();
have.clear();
vc.clear();
int n;
cin >> n;
map<int, int> xm, ym;
map<int, int> recx, recy;
map<int, int> szx, szy;
vector<pair<int, int>> points(2 * n + 3);
map<pair<int, int>, int> idx;
f(i, 1, 2 * n + 1) {
cin >> points[i].first >> points[i].second;
szx[points[i].first]++;
szy[points[i].second]++;
idx[{points[i].first, points[i].second}] = i;
}
int xrate = 1, yrate = szx.size() + 1;
vc = vector<vector<int>>(szx.size() + szy.size() + 6);
vis = vector<bool>(szx.size() + szy.size() + 6);
tree = vector<vector<int>>(szx.size() + szy.size() + 6);
int st = -1;
f(i, 1, 2 * n + 1) {
int x, y;
x = points[i].first, y = points[i].second;
if(!xm[x]) {
xm[x] = xrate;
xrate++;
}
if(!ym[y]) {
ym[y] = yrate;
yrate++;
}
int xn = xm[x], yn = ym[y];
recx[xn] = x, recy[yn] = y;
recx[yn] = -INT_MAX;
recy[xn] = -INT_MAX;
vis[xn] = false;
vis[yn] = false;
vc[xn].push_back(yn);
vc[yn].push_back(xn);
if(st == -1) {
st = xn;
}
have.insert(xn);
have.insert(yn);
}
while(!have.empty()) {
tree.clear();
done.clear();
int get = *have.begin();
dfs(get, 0);
bool dontcare = tre(get, 0, get);
}
cout << pairs.size() << "\n";
set<int> sans;
f(i, 1, 2 * n + 1)
sans.insert(i);
for(auto x : pairs) {
if(recx[x.first] != -INT_MAX) {
int getx = recx[x.first];
int gety1 = recy[x.second.first], gety2 = recy[x.second.second];
cout << idx[{getx, gety1}] << " " << idx[{getx, gety2}] << "\n";
sans.erase(idx[{getx, gety1}]);
sans.erase(idx[{getx, gety2}]);
}
else {
int gety = recy[x.first];
int getx1 = recx[x.second.first], getx2 = recx[x.second.second];
cout << idx[{getx1, gety}] << " " << idx[{getx2, gety}] << "\n";
sans.erase(idx[{getx1, gety}]);
sans.erase(idx[{getx2, gety}]);
}
}
vector<int> copy;
for(auto x : sans)
copy.push_back(x);
for(i = 0; i + 1 < copy.size(); i += 2) {
cout << copy[i] << " " << copy[i + 1] << "\n";
}
return;
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t1 = 1;
cin >> t1;
while (t1--) {
solve();
}
return 0;
}