#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-b.x, dy=(ll)a.y-b.y; return dx*dx+dy*dy;}
unsigned long long rot(unsigned long long n, unsigned long long x, unsigned long long y, unsigned long long rx, unsigned long long ry){
if(ry==0){
if(rx==1){
x = n-1 - x;
y = n-1 - y;
}
unsigned long long t = x; x = y; y = t;
}
return (x<<32) | y;
}
unsigned long long hilbertKey(int x, int y, int bits=21){
unsigned long long rx, ry, s;
unsigned long long hx=0;
unsigned long long X = x, Y = y;
for(int i=bits-1;i>=0;--i){
rx = (X>>i)&1ull;
ry = (Y>>i)&1ull;
unsigned long long idx = (rx<<1) | ry;
hx = (hx<<2) | idx;
}
return hx;
}
void two_opt(vector<P>& pts, vector<int>& tour){
int n = 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);
} else {
// rare because we ensure i1<=j except wrap avoided
}
improved=true;
goto next_outer;
}
}
}
next_outer: ;
}
}
double tour_length(const vector<P>& pts, const vector<int>& tour){
int n=tour.size(); if(n==0) return 0.0;
double s=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){
// initial tour is current order
// apply 2-opt
two_opt(pts, clusters[k]);
}
// compute centroids
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}; }
// iterative balancing rounds
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(clusters[worst].size()<=1) break;
// pick candidate cities: those incident to the longest edges
int m = 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 = 1e-9; int best_k = -1; int best_insert_pos = -1;
for(int k=0;k<K;++k){ if(k==worst) continue;
// quick filter by centroid distance
double dx = pts[u].x - cent[k].first; double dy = pts[u].y - cent[k].second;
double cen_dist2 = dx*dx+dy*dy;
// evaluate insertion cost into cluster k
int mk = 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; }
}
// removal delta
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){
// perform move
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]);
// update centroids
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;
}
// final output
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;
}