#define _CRT_SECURE_NO_WARNINGS
#ifdef _DEBUG

#else
#include "triangles.h"
#endif // _DEBUG

#include <iostream>
#include <vector>
#include <cstdint>
#include <algorithm>

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

#ifdef _DEBUG



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);

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);
}
#endif // _DEBUG

vector<int> st;

bool cmp(int f, int s) {
	vector<Triangle> l = { Triangle(0, 1, f) };
	vector<Triangle> r = { Triangle(0, 1, s) };
	return compare(l, r) <= 0;
}
vector<vector<int>> ans;

void make4(int z[]) {
	for (int i = 0; i < 4; i++)
	{
		int a = z[i], b = z[(i + 1) % 4], c = z[(i + 2) % 4], d = z[(i + 3) % 4];
		Triangle abc(a, b, c);
		Triangle abd(a, b, d);
		Triangle acd(a, c, d);
		Triangle bcd(b,c, d);
		if (compare({ abc,abd,acd }, { bcd }) == 0) {
			ans.push_back({a,b,c});
			ans.push_back({a,b,d});
			ans.push_back({a,c,d});
			return;
		}
	}
	for (int i = 1; i < 4; i++)
	{
		int x = -1, y = -1;
		for (int j = 1; j < 4; j++)
		{
			if (j == i)continue;
			y = j;
			if (x == -1)x = j;
		}
		Triangle x0y(z[x], z[0], z[y]);
		Triangle xiy(z[x], z[i], z[y]);
		Triangle ix0(z[i], z[x], z[0]);
		Triangle iy0(z[i], z[y], z[0]);
		if (compare({ x0y,xiy }, { ix0,iy0 }) == 0) {
			ans.push_back({x,0,y});
			ans.push_back({x,i,y});
			return;
		}
	}
}

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

vector<vector<int>> solve(int n) {
	if (n == 4) {
		int z[4];
		for (int i = 0; i < 4; i++)
		{
			z[i] = i;
		}
		make4(z);
		return ans;

	}
	vector<int> a,b;
	st.resize(n);
	a.push_back(2);
	for (int i = 3; i < n; i++)
	{
		vector<Triangle> l = { Triangle(0, 1, i),Triangle(0,1,2) };
		vector<Triangle> r = { Triangle(2,i,0),Triangle(2,i,1) };
		if (compare(l, r) == 0) {
			b.push_back(i);
			continue;
		}
		if (in(1, i, 2, 0)) {
			b.push_back(i);
			continue;
		}
		if (in(0, i, 2, 1)) {
			b.push_back(i);
			continue;
		}
		a.push_back(i);
	}
	sort(all(a), cmp);
	sort(all(b), cmp);
	vector<int> hd;
	if (a.size() % 2 == 0) {
		swap(a, b);
	}
	if (a.size() % 2 == 0) {
		if (a.size() < b.size())swap(a, b);
		reverse(all(a));
		int z[4];
		z[0] = 0;
		z[1] = 1;
		z[2] = a[a.size() - 1];
		z[3] = a[a.size() - 2];
		a.pop_back();
		make4(z);
	}
	else {
		reverse(all(a));
	}
	
	for (int i = 0; i < a.size(); i++)
	{
		hd.push_back(a[i]);
	}
	if (a.size() % 2) {
		hd.push_back(0);
		hd.push_back(1);
	}
	else {
		hd.push_back(0);
		hd.push_back(1);
		hd.push_back(0);
	}
	
	for (int i = 0; i < b.size(); i++)
	{
		hd.push_back(b[i]);
	}
	for (int i = 0; i + 2 < hd.size(); i += 2)
	{
		vector<int> zxc;
		zxc.push_back(hd[i]);
		zxc.push_back(hd[i + 1]);
		zxc.push_back(hd[i + 2]);
		ans.push_back(zxc);
	}

	return ans;
}


#ifdef _DEBUG
int main() {
	freopen("in.txt", "r", stdin);
	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 // _DEBUG
