#include <bits/stdc++.h>

using namespace std;

#ifdef LOCAL

struct Triangle {
    int i, j, k;

    Triangle() = default;
    Triangle(int i_, int j_, int k_) : i(i_), j(j_), k(k_) {}
};

int compare(const std::vector<Triangle>& left, const std::vector<Triangle>& right);

#endif

#ifndef LOCAL
#include "triangles.h"
#endif

const int N = 11000;

using vi = vector<int>;
using tr = Triangle;
using vtr = vector<tr>;

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

bool check_ord(int a, int b, int c, int d) {
    return compare({{a, c, b}, {a, c, d}}, {{b, d, a}, {b, d, c}}) == 0;
}

set<int> g[N];

vector<vi> solve(int n) {
    vi vec;
    for (int k = 0; k < n; k++) {
        if (vec.size() <= 2) {
            for (int x : vec) {
                g[k].insert(x);
                g[x].insert(k);
            }
            vec.push_back(k);
            continue;
        }
        vi nv, rem;
        int cnt = 0;
        vector<int> cool;
        for (int x : vec) {
            if (g[x].size() != 2) {
                //assert(g[x].size() <= 2);
                while (true) {}
            }
            int l = *g[x].begin();
            int r = *g[x].rbegin();
            if (check_inside(x, l, r, k)) {
                rem.push_back(x);
                continue;
            }
            if (!check_ord(k, l, x, r)) {
                cnt++;
                cool.push_back(x);
                g[k].insert(x);
                g[x].insert(k);
            }
            nv.push_back(x);
        }
        if (cnt == 0)
            continue;
        assert(cnt == 2);
        if (rem.empty()) {
            for (int x : cool)
                for (int y : cool)
                    g[x].erase(y);
        }
        for (int x : rem)
            for (int u : g[x])
                g[u].erase(x);
        vec = nv;
        vec.push_back(k);
    }
    return {vec};
}






























#ifdef LOCAL

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() {
    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