#include "triangles.h"
#include <bits/stdc++.h>
using namespace std;

vector<int> hull;
std::vector<std::vector<int>> ans;


mt19937_64 rnd(52);

bool is_inside_triangle(int a, int b, int c, int i) {
    std::vector<Triangle> left = {Triangle(a, b, c)};
    std::vector<Triangle> right = {Triangle(a, b, i), Triangle(a, c, i), Triangle(c, b, i)};
    return compare(left, right) == 0;
}

bool is_convex(int a, int b, int c, int d) {
    std::vector<Triangle> left = {Triangle(a, b, c), Triangle(a, c, d)};
    std::vector<Triangle> right = {Triangle(a, b, d), Triangle(c, b, d)};
    return compare(left, right) == 0;
}

// bool is_new_inside(int j) {
//     int n = hull.size();
//     int L = 2, R = n - 1;
//     while (R - L > 1) {
//         int M = (L + R) / 2;

//     }
//     for (int i = 2; i < n; i++) {
//         if (is_inside_triangle(hull[0], hull[1], hull[i], j)) return true;
//     }
//     return false;
// }

void add_new_outside(int j) {
    int n = hull.size();
    vector<bool> is_right(n);
    for (int i = 0; i < n; i++) {
        if (is_inside_triangle(hull[(i - 1 + n) % n], hull[(i + 1) % n], j, hull[i])) {
            is_right[i] = true;
            is_right[(i - 1 + n) % n] = true;
        }
    }
    for (int i = 0; i < n; i++) {
        if (!is_right[i])
            is_right[i] = is_convex(hull[i], j, hull[(i + 1) % n], hull[(i + 2) % n]);
    }
    int st = -1;
    for (int i = 0; i < n; i++) {
        bool last = is_right[(i - 1 + n) % n];
        if (!last && is_right[i]) {
            st = i;
        }
    }
    if (st == -1) {
        shuffle(ans.begin(), ans.end(), rnd);
        int i = 0;
        int z = 0;
        for (auto& v : ans) {
            if (is_inside_triangle(v[0], v[1], v[2], j)) {
                z = i;
            }
            i++;
        }
        swap(ans[z], ans.back());
        auto v = ans.back();
        ans.pop_back();
        ans.push_back({v[0], v[1], j});
        ans.push_back({v[0], v[2], j});
        ans.push_back({v[2], v[1], j});
        return;
    }
    int f = hull[st];
    int last_right = st;
    vector<int> to_delete;
    for (int i = st; is_right[i]; i = (i + 1) % n) {
        ans.push_back({hull[i], hull[(i + 1) % n], j});
        last_right = i;
        if (i != st)
            to_delete.push_back(i);
    }
    sort(to_delete.rbegin(), to_delete.rend());
    for (int x : to_delete) {
        hull.erase(hull.begin() + x);
    }
    int i = find(hull.begin(), hull.end(), f) - hull.begin();
    hull.insert(hull.begin() + i + 1, j);
}

std::vector<std::vector<int>> solve(int n) {
    vector<int> order(n);
    iota(order.begin(), order.end(), 0);
    shuffle(order.begin(), order.end(), rnd);
    hull = {order[0], order[1], order[2]};
    ans.push_back({order[0], order[1], order[2]});
    for (int i = 3; i < n; i++) {
        int j = order[i];
        // if (is_new_inside(j)) continue;
        add_new_outside(j);
    }
    if (n == 4 && ans.size() == 1) {
        ans.clear();
        hull.clear();
        return solve(n);
    }
    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() {
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    freopen("../in", "r", stdin);
    freopen("../out", "w", stdout);

    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