#include <iostream>
using namespace std;
void Quicksort(int ** tab, int low, int high)
{
int wall = low;
int fN, fW; // zmienne pomocnicze N - number, W - wartość
for (int i = low; i <= high; i++)
{
if (tab[1][i] <= tab[1][high])
{
fN = tab[0][i];
fW = tab[1][i];
tab[0][i] = tab[0][wall];
tab[1][i] = tab[1][wall];
tab[0][wall] = fN;
tab[1][wall] = fW;
wall++;
}
}
if (wall < high)
Quicksort(tab, wall, high);
if (wall - 2 > low)
Quicksort(tab, low, wall - 2);
}
void zgrabna_funkcja(int ** tab, int wymiar)
{
int i = 0, j = 0, k = 0, l = 0;
for (int num = 0; num < wymiar / 3; num++)
{
while (tab[4][tab[0][i] - 1] == 0) // X malejąco
i++;
tab[0][num] = tab[0][i];
while (tab[4][tab[1][j] - 1] == 0) // X rosnąco
j++;
tab[1][num] = tab[1][j];
while (tab[4][tab[2][k] - 1] == 0) // Y malejąco
k++;
tab[2][num] = tab[2][k];
while (tab[4][tab[3][l] - 1] == 0) // Y rosnąco
l++;
tab[3][num] = tab[3][l];
tab[4][tab[0][i] - 1] = 0;
tab[4][tab[1][j] - 1] = 0;
tab[4][tab[2][k] - 1] = 0;
tab[4][tab[3][l] - 1] = 0;
}
}
void ostatnie_porzadki(int ** tab, int wymiar)
{
int supp;
for (int i = 0; i < wymiar / 3; i++)
for (int k = 0; k < 3; k++)
for (int j = 0; j < 3; j++)
if (tab[j][i] > tab[j + 1][i])
{
supp = tab[j][i];
tab[j][i] = tab[j + 1][i];
tab[j + 1][i] = supp;
}
}
void daj_glos(int ** tab, int wymiar)
{
for (int i = 0; i < wymiar / 3; i++)
{
cout << tab[0][i] << " ";
if (tab[1][i] > tab[0][i])
cout << tab[1][i] << " ";
if (tab[2][i] > tab[1][i])
cout << tab[2][i] << " ";
if (tab[3][i] > tab[2][i])
cout << tab[3][i];
cout << endl;
}
}
void f_delete(int ** tabX, int ** tabY, int ** tab5)
{
delete[] tabX[0];
delete[] tabX[1];
delete[] tabX;
delete[] tabY[0];
delete[] tabY[1];
delete[] tabY;
delete[] tab5[0];
delete[] tab5[1];
delete[] tab5[2];
delete[] tab5[3];
delete[] tab5[4];
delete[] tab5;
}
int main()
{
int t; // program ma policzyć t zadań testowych
cin >> t;
while (t--)
{
int LiczbaPunktow; // każde z nich składa się LiczybyPunktow
cin >> LiczbaPunktow; // o współrzędnych X i Y
int& wymiar = LiczbaPunktow;
int ** tabX = new int *[2]; // tworzę dwie niezależne tablice
tabX[0] = new int[wymiar]; // tablica X
tabX[1] = new int[wymiar];
int ** tabY = new int *[2]; // tablica Y
tabY[0] = new int[wymiar]; // które przechodują dwie wartości
tabY[1] = new int[wymiar]; // numer punktu i wartość wpółrzędnej X lub Y
for (int i = 0; i < wymiar; i++)
{
tabX[0][i] = i + 1; // nadanie numerów punktom X
tabY[0][i] = i + 1; // nadanie numerów punktom Y
cin >> tabX[1][i] >> tabY[1][i]; // wczytanie współrzędnych
}
Quicksort(tabX, 0, wymiar - 1); // posortowanie tablicy X
Quicksort(tabY, 0, wymiar - 1); // posortowanie tablicy Y
int ** tab5 = new int *[5]; // deklaracja tablicy, w której przechowywane będę
for (int i = 0; i < 5; i++) // tylko numery punktów, ale w 4 kategoriach
tab5[i] = new int[wymiar];
for (int i = 0; i < wymiar; i++)
{
tab5[0][i] = tabX[0][wymiar - 1 - i]; // X malejąco
tab5[1][i] = tabX[0][i]; // X rosnąco
tab5[2][i] = tabY[0][wymiar - 1 - i]; // Y malejąco
tab5[3][i] = tabY[0][i]; // Y rosnąco
tab5[4][i] = 1; // informacja o wykorzystaniu punktu do budowy trójkąta
} // 0 - niedostępne, 1 - dostępne
zgrabna_funkcja(tab5, wymiar); // sortuje tablicę w taki sposób, aby żaden punkt
// nie został wykorzystany do budowy więcej niż jednego trójkąta
ostatnie_porzadki(tab5, wymiar); // funkcja pomocnicza ustawiająca punkty w kolejności według ich numerów
daj_glos(tab5, wymiar); // wypisuje kolejne trójki numerów punktów
// które składają się na trójkąty ostrokątne
f_delete(tabX, tabY, tab5); // funkcja istniejąca ze względu na aspekt estetyczny
if (t > 0)
cout << endl;
}
cin.get();
cin.get();
return 0;
}