#ifndef LOCAL
#pragma GCC Optimize("O3, Ofast")
#pragma GCC Target("avx,avx2,unroll-loops")
#endif
#include <bits/stdc++.h>
#include "triangles.h"

using namespace std;
using ll = long long;
using ld = long double;

#define f first
#define s second
#define all(x) (x).begin(), (x).end()
#define mp make_pair
#define pb push_back
#define pii pair<int, int>
#ifndef LOCAL
#define endl "\n"
#endif

struct F {
    vector<int> t;
    F(int n) {
        t.assign(n, 0);
    }
    int get(int r) {
        int ans = 0;
        for (; r >= 0; r = (r&(r + 1)) - 1) {
            ans += t[r];
        }
        return ans;
    }
    void upd(int i, int x) {
        for (; i < t.size(); i = (i|(i + 1))) {
            t[i] += x;
        }
    }
};

mt19937 rnd(11);

bool OtherSide(int x, int y, pii s) {
    return compare({Triangle(x, s.f, s.s), Triangle(y, s.f, s.s)}, {Triangle(x, y, s.f), Triangle(x, y, s.s)}) == 0;
}

int findFar(int x, int y, vector<int> &v) {
    int ans = 0;
    for (int i = 1; i < v.size(); ++i) {
        if (compare({Triangle(v[ans], x, y)}, {Triangle(v[i], x, y)}) == -1) {
            ans = i;
        }
    }
    return v[ans];
}

vector<int> ans;
vector<vector<int>> fin;

bool inside(int a, int b, int c, int x) {
    return compare({Triangle(a, b, c)}, {Triangle(a, b, x), Triangle(b, c, x), Triangle(a, c, x)}) == 0;
}

void solve2(int a, int b, int c, vector<int> &v) {
    // cout << "? " << a << ' ' << b << ' ' << c << " : ";
    // for (auto &x : v) {
    //     cout << x << ' ';
    // }
    // cout << endl;
    if (v.empty()) {
        fin.pb({a, b, c});
        return;
    }
    if (rnd()&1) {
        swap(a, b);
    }
    if (rnd()&1) {
        swap(b, c);
    }
    if (rnd()&1) {
        swap(a, c);
    }
    int ind = rnd() % v.size();
    vector<int> ab, bc, ac;
    for (int i = 0; i < v.size(); ++i) {
        if (i == ind) {
            continue;
        }
        if (inside(a, b, v[ind], v[i])) {
            ab.pb(v[i]);
        } else if (inside(b, c, v[ind], v[i])) {
            bc.pb(v[i]);
        } else {
            ac.pb(v[i]);
        }
    }
    solve2(a, b, v[ind], ab);
    solve2(b, c, v[ind], bc);
    solve2(c, a, v[ind], ac);
}

void rec(int a, int b, vector<int> v) {
    if (v.empty()) {
        return;
    }
    int best = findFar(a, b, v);
    vector<int> fst, scd;
    vector<int> todo;
    for (auto &x : v) {
        if (x == best) {
            continue;
        }
        if ((rnd()&1)) {
            if (inside(a, b, best, x)) {
                todo.pb(x);
            } else {
            if (OtherSide(b, x, mp(a, best))) {
                fst.pb(x);
            } else {
                scd.pb(x);
            }}
        } else {
            if (OtherSide(a, x, mp(b, best))) {
                scd.pb(x);  
            } else {
            if (OtherSide(b, x, mp(a, best))) {
                fst.pb(x);
            } else {
                todo.pb(x);
            }}            
        }
    }
    rec(a, best, fst);
    ans.pb(best);
    rec(best, b, scd);
    // solve2(a, best, b, todo);
}

std::vector<std::vector<int>> solve(int n) {
    pii s = mp((rnd() % (n - 1)), 1 + rnd() % (n - 1));
    while (s.f == s.s) {
        s.s = 1 + (rnd() % (n - 1));
    }
    vector<int> v;
    for (int i = 0; i < n; ++i) {
        if (i != s.f && i != s.s) {
            v.pb(i);
        }
    }
    int best = findFar(s.f, s.s, v);
    v.clear();
    for (int i = 0; i < n; ++i) {
        if (i == s.f) {
            continue;
        }
        if (i != best) {
            v.pb(i);
        }
    }
    int best2 = findFar(s.f, best, v);
    ans = {best};
    vector<int> left = {s.f}, right = {};
    for (int i = 0; i < n; ++i) {
        if (i == best || i == best2 || i == s.f) {
            continue;
        }
        if (OtherSide(left[0], i, mp(best, best2))) {
            right.pb(i);
        } else {
            left.pb(i);
        }
    }
    rec(best, best2, left);
    ans.pb(best2);
    rec(best2, best, right);
    return {ans};
}

#ifdef LOCAL
#include "triangles.h"
#include <iostream>
#include <vector>
#include <cstdint>

using namespace std;

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) {
            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() {
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);

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

    auto result = solve(n);

    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()];
        }
    }
    if (verbose > 0) {
        cout << cur_queries << (cur_queries == 1 ? " query\n" : " queries\n");
    }

    return 0;
}
#endif