//  ↘ ⬇ ⬇ ⬇ ⬇ ⬇ ↙
//  ➡ @roadfromroi ⬅
//  ↗ ⬆ ⬆ ⬆ ⬆ ⬆ ↖
/*
░░░░░░░█▐▓▓░████▄▄▄█▀▄▓▓▓▌█
░░░░░▄█▌▀▄▓▓▄▄▄▄▀▀▀▄▓▓▓▓▓▌█
░░░▄█▀▀▄▓█▓▓▓▓▓▓▓▓▓▓▓▓▀░▓▌█
░░█▀▄▓▓▓███▓▓▓███▓▓▓▄░░▄▓▐█▌
░█▌▓▓▓▀▀▓▓▓▓███▓▓▓▓▓▓▓▄▀▓▓▐█
▐█▐██▐░▄▓▓▓▓▓▀▄░▀▓▓▓▓▓▓▓▓▓▌█▌
█▌███▓▓▓▓▓▓▓▓▐░░▄▓▓███▓▓▓▄▀▐█
█▐█▓▀░░▀▓▓▓▓▓▓▓▓▓██████▓▓▓▓▐█
▌▓▄▌▀░▀░▐▀█▄▓▓██████████▓▓▓▌█▌
▌▓▓▓▄▄▀▀▓▓▓▀▓▓▓▓▓▓▓▓█▓█▓█▓▓▌█▌
█▐▓▓▓▓▓▓▄▄▄▓▓▓▓▓▓█▓█▓█▓█▓▓▓▐█ йоу
 */
#include <iostream>
#include "vector"
#include "algorithm"
#include "numeric"
#include "climits"
#include "random"
#include "iomanip"
#include "bitset"
#include "cmath"
#include "map"
#include "deque"
#include "array"
#include "set"
#include "triangles.h"

#define all(x) x.begin(), x.end()
using namespace std;

bool bigger(int a, int b, int c, int d) {
    //return abc < abd
    return compare({Triangle{a, b, c}}, {Triangle{a, b, d}})==-1;
}
bool isord(int s0, int a, int b, int c) {
    // returns 1 if a < b < c (or a > b > c) ray order from s0
    return (compare({{a, c, s0}, {a, c, b}}, {{s0, b, a}, {s0, b, c}})==0)
    or (compare({{s0, a, c}}, {{s0, a, b}, {s0, c, b}, {a, c, b}}) == 0);
}
bool takeornot(int s0, int a, int b, int c) {
    // a < b < c
    // return 0 if b is meaningful
    return (compare({{s0, a, c}}, {{s0,a,b},{s0,b,c}}) > 0);
}
bool downorup(int s0, int a, int b, int trg) {
    // up - 1
    return takeornot(s0, a, trg, b) == 0;
}
mt19937 rnd;
vector<vector<int>> operator+(vector<vector<int>> a, vector<vector<int>> b) {
    for (auto i : b)
        a.push_back(i);
    return a;
}
void operator+=(vector<vector<int>> &a, vector<vector<int>> b) {
    for (auto i : b)
        a.push_back(i);
}
vector<vector<int>> trianguling(int a, int b, int c, vector<int> nubes) {
    // somehow it is garanteed that b < nubes < c and nubes are sorted
    if (nubes.empty()) {
        return {{a, b, c}};
    }
    if (nubes.size() == 1) {
        return {{a, b, nubes[0]}, {a, c, nubes[0]}, {b, c, nubes[0]}};
    }
    int v = rnd() % nubes.size();
    vector<int> al, ar, alr;
    for (int i = 0; i < nubes.size(); ++i) {
        if (i < v) {
            if (downorup(a, b, nubes[v], nubes[i]))
                alr.push_back(i);
            else
                al.push_back(i);
        }
        if (v < i) {
            if (downorup(a, nubes[v], c, nubes[i]))
                alr.push_back(i);
            else
                ar.push_back(i);
        }
    }
    return trianguling(a, b, nubes[v], al) + trianguling(nubes[v], b, c, alr) + trianguling(a, nubes[v], c, ar);
}
vector<vector<int>> solve(int n) {
    int v = 2;
    for (int i = 3; i < n; ++i) {
        if (bigger(0, 1, v, i))
            v = i;
    }
    //cerr << v << endl;
    int v1 = 0;
    int v2 = 1;
    for (int i = 2; i < n; ++i) {
        if (i != v) {
            if (isord(v, i, v1, v2)) {
                v2 = v1;
                v1 = i;
            }
        }
    }
    //cerr << v << ' ' << v1 << ' ' << v2 << isord(v, 2, 0, 1) << '\n';
    auto cmp = [&](int a, int b) {
        return isord(v, v1, a, b);
    };
    vector<int> numa;
    for (int i = 0; i < n; ++i) {
        if (i != v1 and i != v)
            numa.push_back(i);
    }
    sort(all(numa), cmp);
    vector<int> vipuk = {v, v1};
    vipuk.push_back(numa[0]);
    for (int i = 1; i < numa.size(); ++i) {
        while (vipuk.size() != 2 and takeornot(v, vipuk[vipuk.size()-2], vipuk[vipuk.size()-1], numa[i])) {
            vipuk.pop_back();
        }
        vipuk.push_back(numa[i]);
    }
    for (auto i : vipuk)
        cerr << i << ' ';
    cerr << '\n';
    vector<vector<int>> res;
    vector<int> a;
    int st = vipuk[1];
    int ind = 0;
    for (int i = 2; i < vipuk.size(); ++i) {
        while (numa[ind] != vipuk[i]) {
            a.push_back(numa[ind]);
            ind++;
        }
        ind++;
        res += trianguling(v, st, vipuk[i], a);
        cerr << v << ' ' << st << ' ' << vipuk[i] << '\n';
        a.clear();
        st = vipuk[i];
    }
    return res;
}


#ifdef __APPLE__
namespace {
    constexpr int kMaxQ = 2'000'000;
    int verbose = 0;

    void WA(const string& msg) {
        cout << "WA " << msg << "\n";
        exit(0);
    }

    int n, group;
    vector<pair<int64_t, int64_t>> points;
    uint64_t cur_queries;

    void ValidateTriangle(const Triangle& t) {
        if (t.i < 0 || t.i >= n) {
            WA("triangle i is out of range [0,n-1]");
        }
        if (t.j < 0 || t.j >= n) {
            WA("triangle j is out of range [0,n-1]");
        }
        if (t.k < 0 || t.k >= n) {
            WA("triangle k is out of range [0,n-1]");
        }
        if (t.i == t.j) {
            WA("triangle i and j are equal");
        }
        if (t.i == t.k) {
            exit(1);
            WA("triangle i and k are equal");
        }
        if (t.j == t.k) {
            WA("triangle j and k are equal");
        }
    }

    uint64_t GetDoubleArea(const Triangle& t) {
        pair<int64_t, int64_t> v1 = {points[t.j].first - points[t.i].first, points[t.j].second - points[t.i].second};
        pair<int64_t, int64_t> v2 = {points[t.k].first - points[t.i].first, points[t.k].second - points[t.i].second};
        return abs(v1.first * v2.second - v1.second * v2.first);
    }

    void LogCompare(const vector<Triangle>& left, const vector<Triangle>& right) {
        cout << "compare #" << cur_queries << ":\n";
        cout << "left " << left.size() << " triangle" << (left.size() > 1 ? "s" : "") << ": ";
        for (size_t i = 0; i < left.size(); ++i) {
            cout << (i == 0 ? "(" : ", (") << left[i].i << "," << left[i].j << "," << left[i].k << ")";
        }
        cout << "\n";
        cout << "right " << right.size() << " triangle" << (right.size() > 1 ? "s" : "") << ": ";
        for (size_t i = 0; i < left.size(); ++i) {
            cout << (i == 0 ? "(" : ", (") << right[i].i << "," << right[i].j << "," << right[i].k << ")";
        }
        cout << "\n";
    }
}

int compare(const vector<Triangle>& left, const vector<Triangle>& right) {
    cur_queries++;
    if (cur_queries > kMaxQ) {
        WA("too many queries");
    }
    if (verbose > 0) {
        LogCompare(left, right);
    }
    if (left.empty()) {
        WA("left should be non-empty");
    }
    if (right.empty()) {
        WA("right should be non-empty");
    }
    if (left.size() + right.size() > 4) {
        WA("the number of triangles should be at most 4");
    }
    for (const auto& t : left) {
        ValidateTriangle(t);
    }
    for (const auto& t : right) {
        ValidateTriangle(t);
    }

    uint64_t left_area = 0;
    for (const auto& t : left) {
        left_area += GetDoubleArea(t);
    }
    uint64_t right_area = 0;
    for (const auto& t : right) {
        right_area += GetDoubleArea(t);
    }

    if (verbose > 0) {
        cout << "result: ";
        if (left_area < right_area) {
            cout << "left is smaller (-1)\n";
        } else if (left_area == right_area) {
            cout << "equal (0)\n";
        } else {
            cout << "right is smaller (1)\n";
        }
    }
    return left_area < right_area ? -1 : (left_area > right_area ? 1 : 0);
}

int main() {
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);

    cin >> n >> group;
    points.resize(n);
    for (int i = 0; i < n; ++i) {
        cin >> points[i].first >> points[i].second;
    }
    cur_queries = 0;

    auto result = solve(n, group);

    cout << result.size() << "\n";
    for (const auto& polygon : result) {
        cout << polygon.size() << "\n";
        for (size_t i = 0; i < polygon.size(); ++i) {
            cout << polygon[i] << " \n"[i + 1 == polygon.size()];
        }
    }
    cout << cur_queries << (cur_queries == 1 ? "query" : " queries\n");

    return 0;
}
#endif