#include <bits/stdc++.h>
using namespace std;
using ll = long long;
struct P { int x, y, id; };
static inline ll dist2(const P &a, const P &b) {
ll dx = (ll)a.x - (ll)b.x;
ll dy = (ll)a.y - (ll)b.y;
return dx*dx + dy*dy;
}
unsigned long long hilbertKey(int x, int y, int bits = 21) {
unsigned long long hx = 0;
unsigned long long X = (unsigned long long)x, Y = (unsigned long long)y;
for (int i = bits - 1; i >= 0; --i) {
unsigned long long rx = (X >> i) & 1ull;
unsigned long long ry = (Y >> i) & 1ull;
unsigned long long idx = (rx << 1) | ry;
hx = (hx << 2) | idx;
}
return hx;
}
void two_opt(const vector<P> &pts, vector<int> &tour) {
int n = (int)tour.size();
if (n <= 3) return;
bool improved = true;
int iter = 0;
while (improved && iter < 200) {
improved = false; ++iter;
for (int i = 0; i < n; ++i) {
int i1 = (i + 1) % n;
P A = pts[tour[i]];
P B = pts[tour[i1]];
for (int j = i + 2; j < n; ++j) {
if (i == 0 && j == n - 1) continue;
int j1 = (j + 1) % n;
P C = pts[tour[j]];
P D = pts[tour[j1]];
ll before = dist2(A, B) + dist2(C, D);
ll after = dist2(A, C) + dist2(B, D);
if (after < before) {
if (i1 <= j) reverse(tour.begin() + i1, tour.begin() + j + 1);
improved = true;
goto next_outer;
}
}
}
next_outer: ;
}
}
double tour_length(const vector<P> &pts, const vector<int> &tour) {
int n = (int)tour.size();
if (n == 0) return 0.0;
double s = 0.0;
for (int i = 0; i < n; ++i) {
int j = (i + 1) % n;
s += sqrt((double)dist2(pts[tour[i]], pts[tour[j]]));
}
return s;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N, K;
if (!(cin >> N >> K)) return 0;
vector<P> pts(N);
for (int i = 0; i < N; ++i) { cin >> pts[i].x >> pts[i].y; pts[i].id = i; }
vector<pair<unsigned long long,int>> ord; ord.reserve(N);
int bits = 21;
for (int i = 0; i < N; ++i) ord.emplace_back(hilbertKey(pts[i].x, pts[i].y, bits), i);
sort(ord.begin(), ord.end());
vector<int> perm; perm.reserve(N);
for (auto &pr : ord) perm.push_back(pr.second);
vector<int> sizes(K, N / K);
for (int i = 0; i < N % K; ++i) sizes[i]++;
vector<vector<int>> clusters(K);
int idx = 0;
for (int k = 0; k < K; ++k) {
int s = sizes[k];
clusters[k].reserve(s);
for (int t = 0; t < s; ++t) clusters[k].push_back(perm[idx++]);
}
for (int k = 0; k < K; ++k) two_opt(pts, clusters[k]);
vector<pair<double,double>> cent(K);
for (int k = 0; k < K; ++k) {
double sx = 0, sy = 0;
for (int id : clusters[k]) { sx += pts[id].x; sy += pts[id].y; }
int sz = max(1, (int)clusters[k].size());
cent[k] = { sx / sz, sy / sz };
}
int max_rounds = 1000;
for (int round = 0; round < max_rounds; ++round) {
vector<double> lens(K);
for (int k = 0; k < K; ++k) lens[k] = tour_length(pts, clusters[k]);
int worst = max_element(lens.begin(), lens.end()) - lens.begin();
bool moved = false;
if ((int)clusters[worst].size() <= 1) break;
int m = (int)clusters[worst].size();
vector<pair<double,int>> edge_contrib; edge_contrib.reserve(m);
for (int i = 0; i < m; ++i) {
int j = (i + 1) % m;
double d = sqrt((double)dist2(pts[clusters[worst][i]], pts[clusters[worst][j]]));
edge_contrib.emplace_back(d, i);
}
sort(edge_contrib.rbegin(), edge_contrib.rend());
int tries = min(8, (int)edge_contrib.size());
for (int tt = 0; tt < tries && !moved; ++tt) {
int pos = edge_contrib[tt].second;
int u = clusters[worst][pos];
double best_delta = 1e100;
int best_k = -1;
int best_insert_pos = -1;
for (int k = 0; k < K; ++k) {
if (k == worst) continue;
int mk = (int)clusters[k].size();
if (mk == 0) continue;
double best_ins = 1e100; int bi = -1;
for (int i = 0; i < mk; ++i) {
int ni = (i + 1) % mk;
double before = sqrt((double)dist2(pts[clusters[k][i]], pts[clusters[k][ni]]));
double after = sqrt((double)dist2(pts[clusters[k][i]], pts[u])) + sqrt((double)dist2(pts[u], pts[clusters[k][ni]]));
double delta = after - before;
if (delta < best_ins) { best_ins = delta; bi = ni; }
}
int prev = (pos - 1 + m) % m;
int next = (pos + 1) % m;
double rem_before = sqrt((double)dist2(pts[clusters[worst][prev]], pts[clusters[worst][pos]]))
+ sqrt((double)dist2(pts[clusters[worst][pos]], pts[clusters[worst][next]]));
double rem_after = sqrt((double)dist2(pts[clusters[worst][prev]], pts[clusters[worst][next]]));
double delta_total = best_ins + (rem_after - rem_before);
if (delta_total < best_delta) { best_delta = delta_total; best_k = k; best_insert_pos = bi; }
}
if (best_k != -1 && best_delta < -1e-7) {
clusters[worst].erase(clusters[worst].begin() + pos);
clusters[best_k].insert(clusters[best_k].begin() + best_insert_pos, u);
two_opt(pts, clusters[worst]);
two_opt(pts, clusters[best_k]);
for (int t = 0; t < 2; ++t) {
int kk = (t == 0 ? worst : best_k);
double sx = 0, sy = 0;
for (int id2 : clusters[kk]) { sx += pts[id2].x; sy += pts[id2].y; }
int sz = max(1, (int)clusters[kk].size());
cent[kk] = { sx / sz, sy / sz };
}
moved = true;
}
}
if (!moved) break;
}
for (int k = 0; k < K; ++k) {
cout << clusters[k].size();
for (int id : clusters[k]) cout << ' ' << pts[id].id + 1;
cout << "\n";
}
return 0;
}