#include <cstdlib>
#include <array>
#include <iostream>
#include <limits>
#include <vector>

const double metricEps = 1e-10;
const double metricEps2 = metricEps * metricEps;

struct Point2
{
    Point2() {};
    Point2(
        int _x,
        int _y,
        int _i)
    :   x(_x),
        y(_y),
        i(_i)
    {}

    double operator%(const Point2& point) const
    {
        return x * point.y - y * point.x;
    };

    Point2 operator-(const Point2& point) const
    {
        return Point2(x - point.x, y - point.y, i);
    }

    Point2 operator+(const Point2& point) const
    {
        return Point2(x + point.x, y + point.y, i);
    }

    double distance2(const Point2& point) const
    {
        double dx = x - point.x;
        double dy = y - point.y;
        return dx * dx + dy * dy;
    }

    int x;
    int y;
    int i;
};

struct Line2
{
    Point2 beg, end;

    double distance2(const Point2& point) const
    {
        double area = ((beg - point) % (end - point)) / 2.0;
        return area * area / beg.distance2(end);
    }
};

typedef std::array<std::size_t, 3> Triangle;

typedef std::vector<Point2> Cloud;

Triangle FindTriangle(const Cloud& cloud)
{
    Triangle triangle;
    triangle[0] = 0;
    triangle[1] = 1;

    Line2 line;
    line.beg = cloud[triangle[0]];
    line.end = cloud[triangle[1]];

    double minDistance2 = std::numeric_limits<double>::max();
    for (std::size_t pointId = 0; pointId < cloud.size(); pointId++)
    {
        const Point2& point = cloud[pointId];
        double distance2 = line.distance2(point);
        if (distance2 > metricEps2)
        {
            if (distance2 < minDistance2 - metricEps2)
            {
                minDistance2 = distance2;
                triangle[2] = pointId;
            }
        }
        else
        {
            double distToBeg2 = line.beg.distance2(point);
            if ((distToBeg2 > metricEps2) && (distToBeg2 < line.beg.distance2(line.end) - metricEps2))
            {
                line.end = point;
                triangle[1] = pointId;
            }
        }
    }

    return triangle;
}

Cloud ReadPoints()
{
    std::size_t nPoints = 0;
    std::cin >> nPoints;

    Cloud points(nPoints, Point2(0, 0, 0));

    for (std::size_t i = 0; i < nPoints; ++i)
    {
        int x, y;
        std::cin >> x >> y;
        points[i] = Point2(x, y, i + 1);
    }

    return points;
}

int main()
{
    Cloud cloud = ReadPoints();
    Triangle triangle = FindTriangle(cloud);

    std::cout << cloud[triangle[0]].i << ' ' << cloud[triangle[1]].i << ' ' << cloud[triangle[2]].i;

    return 0;
}


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

//---------------------------------------------------------------------------------------------------------------------

struct Point2 {
    Point2(int xx, int yy) : x(xx), y(yy) {}
    Point2() = default;

	int x;
	int y;
};

int compare_x_coord(const void* p1, const void* p2) {
	return reinterpret_cast<const Point2*>(p1)->x - reinterpret_cast<const Point2*>(p2)->x;
}

int compare_y_coord(const void* p1, const void* p2) {
	return reinterpret_cast<const Point2*>(p1)->y - reinterpret_cast<const Point2*>(p2)->y;
}

/*---------------------------------------------------Задача 1----------------------------------------------------------
В заданном облаке точек на плоскости (каждая точка определяется двумя целочисленными координатами: x, y) найти 3 любые точки,
которые образуют невырожденный треугольник (имеющий ненулевую площадь). Все остальные точки должны находиться строго за пределами этого треугольника.
Заданные точки не принадлежат одной прямой.
Никакие две точки не находятся в одной позиции.
Количество точек может быть от 3 до 1е5.
Каждая из заданных координат может находиться в пределах от -1е9 до 1е9.
Метод Solve() принимает облако точек, заданных в плоскости, и возвращает 3 индекса точек из заданного облака,
удовлетворяющих решению поставленной задачи.*/

struct Point2_Index : Point2 {
	size_t index;
};

inline bool PointsOnTheLine(const Point2& p1, const Point2& p2, const Point2& p3)  {
	return  static_cast<std::int64_t>(p2.x-p1.x) * (p3.y-p1.y)  -  static_cast<std::int64_t>(p3.x-p1.x) * (p2.y-p1.y)  ==  0;
}

std::array<std::size_t, 3> Solve(const std::vector<Point2>& points) {
	std::array<std::size_t, 3> result = {1000000, 1000000, 1000000}; // initialize with invalid indices
	std::vector<Point2_Index> points_indices(points.size());
	size_t i;
	for(i=0; i<points_indices.size(); i++) { // copy unsorted points and create successive indices
		points_indices[i].x = points[i].x;
		points_indices[i].y = points[i].y;
		points_indices[i].index = i;
	}
	std::qsort(&points_indices[0], points_indices.size(), sizeof(Point2_Index), compare_x_coord); // order by ascending x coordinate.

	auto p1 = points_indices.begin(), // first point
		 p2 = p1+1; // second point

	if(p2->x == p1->x) { // 2 (or more) points with the same x coordinate=p1.x
		p2++; // p2=3rd point
		while(p2 != points_indices.end()  &&  p2->x == p1->x) p2++; // find the end of the range with x coordinate=p1.x. the end will be assigned to p2
		if(p2 == points_indices.end()) return result; // bad input. all points are on the same line X=p1.x
		i = std::distance(p1, p2); // save i - index of the first element p2: p2.x!=p1.x
		std::qsort(std::addressof(*p1), i, sizeof(Point2_Index), compare_y_coord); // order subset {x coordinate=p1.x} by ascending y coordinate.
		result[0] = points_indices[0].index; // 2 first points with the same x coordinate=p1.x and ascending y coordinates
		result[1] = points_indices[1].index;
		result[2] = points_indices[i].index; // a point with a different x coordinate=p2.x
	}

	else { // 2 points with different x coordinates
		auto p3 = p2+1; // p3=3rd point
		do {

			while(p3 != points_indices.end()  &&  p3->x == p2->x) p3++; // find the end of the range with x coordinate=p2.x. the end will be assigned to p3

			if(std::distance(p2, p3) > 1) { // there are 2 (or more) points in subset {x coordinate=p2.x}
				i=std::distance(p1, p2); // save p2 iterator index before sorting
				std::qsort(std::addressof(*p2), std::distance(p2, p3), sizeof(Point2_Index), compare_y_coord); // order subset {x coordinate=p2.x} by ascending y coordinate
				p2 = points_indices.begin() + i; // restore p2 iterator index after sorting
				p3 = p2 + 1; // restore p3 iterator index after sorting
				break;
				/* output will be:
				result[0] = p1->index; // p1.x
				result[1] = p2->index; // p2.x<p1.x, p2.y==max_y
				result[2] = (p2+1)->index; // p3.x==p2.x, p3.y==previous(max_y)
				return result;
				*/
			}

			// else there is only 1 point with x coordinate=p2.x
			if(!PointsOnTheLine(*p1, *p2, *p3)) { // luck! (p1,p2,p3) are not on the same line
				break;
				/* output will be:
				result[0] = p1->index; // p1.x
				result[1] = p2->index; // p2.x<p1.x
				result[2] = p3->index; // p3.x<p2.x and (p1,p2,p3) are not on the same line
				return result;
				*/
			}

			// else (p1,p2,p3) are on the same line. consider p1=p2, p2=p3, p3=p2+1 and run check again
			p1 = p2;
			p2 = p3;
			p3 = p2+1;

		} while(true);
		result[0] = p1->index;
		result[1] = p2->index;
		result[2] = p3->index;
	}

	return result;
}

/*---------------------------------------------------Задача 2----------------------------------------------------------
В заданном облаке точек на плоскости (каждая точка определяется двумя целочисленными координатами: x, y) найти пару точек
с кратчайшим расстоянием между друг другом среди всех пар точек.
Количество точек может быть от 2 до 1е6.
Каждая из заданных координат может находиться в пределах от -1е9 до 1е9.
Метод FindMinDistance() принимает облако точек, заданных в плоскости, и возвращает дистанцию между двумя ближайшими точками в заданном облаке. */

//inline std::int64_t distance2(const Point2& a, const Point2& b) {
//	int dx = a.x-b.x, dy = a.y-b.y;
//	return static_cast<std::int64_t>(dx)*dx + static_cast<std::int64_t>(dy)*dy; // square of distance
//}
//
//
//std::int64_t find_min_distance2_brute(const std::vector<Point2>& points) { // find minimal square of distance - brute
//	std::int64_t d2,
//			min_d2 = 8000000000000000000; // set current min square to max possible value: 2e9^2 + 2e9^2
//	for(auto i = points.begin(); i < points.end()-1; i++)
//		for(auto j = i+1; j < points.end(); j++) {
//			d2=distance2(*i, *j);
//			if(d2 < min_d2) {
//				if(d2 == 1) return 1; // luck, found min possible distance in given space
//				min_d2 = d2;
//			}
//		}
//	return min_d2;
//}
//
//
//std::int64_t find_min_distance2(const std::vector<Point2>& point_sorted_x, const std::vector<Point2>& point_sorted_y) { // find minimal square of distance - smart
//	if(point_sorted_x.size() <= 3)	return find_min_distance2_brute(point_sorted_x);
//
//	size_t im = point_sorted_x.size()/2; // median point index
//	const int xm = point_sorted_x[im].x; // x coordinate of a median point
//	std::vector<Point2> points_left_subset_sorted_x, points_left_subset_sorted_y, // here we will put points with x <= point[im].x, one subset ordered by x, one by y
//						points_right_subset_sorted_x, points_right_subset_sorted_y, // here we will put points with x > point[im].x, one subset ordered by x, one by y
//						points_stripe_subset_sorted_y; // here we will put points p: |p.x-xm|<some distance value. this subset is ordered by y
//
//	// fill the left and right subsets:
//	std::copy(std::begin(point_sorted_x), std::begin(point_sorted_x) + im, std::back_inserter(points_left_subset_sorted_x));
//	std::copy(std::begin(point_sorted_x) + im, std::end(point_sorted_x), std::back_inserter(points_right_subset_sorted_x));
//	std::copy_if(std::begin(point_sorted_y), std::end(point_sorted_y), std::back_inserter(points_left_subset_sorted_y),
//		[&xm](const Point2& p) {	return p.x <= xm;	});
//	std::copy_if(std::begin(point_sorted_y), std::end(point_sorted_y), std::back_inserter(points_right_subset_sorted_y),
//		[&xm](const Point2& p) {	return p.x > xm;	});
//
//	// find minimal square of distance in left subset, right subset and choose minimum of those 2 values:
//	std::int64_t min_d2_left = find_min_distance2(points_left_subset_sorted_x, points_left_subset_sorted_y),
//			min_d2_right = find_min_distance2(points_right_subset_sorted_x, points_right_subset_sorted_y),
//			min_d2 = min_d2_right <= min_d2_left ? min_d2_right : min_d2_left;
//
//	if(min_d2 == 1) return 1; // luck, found min possible distance in given space
//
//	float min_d = sqrtf(static_cast<float>(min_d2)); // min distance
//
//	// fill stripe subset:
//	std::copy_if(std::begin(point_sorted_y), std::end(point_sorted_y), std::back_inserter(points_stripe_subset_sorted_y),
//		[&xm, &min_d](const Point2& p) { return abs(xm-p.x) < min_d; });
//
//	// analyze stripe subset for feasible closest points:
//	for(auto i = points_stripe_subset_sorted_y.begin(); i < points_stripe_subset_sorted_y.end()-1; i++)
//		for(auto j = i+1; j<points_stripe_subset_sorted_y.end(); j++) {
//			if(abs(j->y-i->y) >= min_d) break; /* points i and j are not qualified as feasible closest candidates
//												  because y-distance is further than found min distance, proceed with next i index */
//			std::int64_t d2 = distance2(*i, *j); // square of distance between points i and j
//			if(d2 < min_d2) {
//				if(d2 == 1) return 1; // luck, found min possible distance in given space
//				min_d2 = d2;
//				min_d = sqrtf(static_cast<float>(min_d2));
//			}
//		}
//
//	return min_d2;
//}
//
//
//float FindMinDistance(const std::vector<Point2>& points) {
//	auto point_sorted_x(points), point_sorted_y(points);
//	std::qsort(&point_sorted_x[0], point_sorted_x.size(), sizeof(Point2), compare_x_coord);
//	std::qsort(&point_sorted_y[0], point_sorted_y.size(), sizeof(Point2), compare_y_coord);
//	return sqrtf(static_cast<float>(find_min_distance2(point_sorted_x, point_sorted_y)));
//}
//---------------------------------------------------------------------------------------------------------------------

typedef std::vector<Point2> Points;

Points ReadPoints()
{
    std::size_t nPoints = 0;
    std::cin >> nPoints;

    Points points(nPoints, Point2(0, 0));

    for (std::size_t i = 0; i < nPoints; ++i)
    {
        int x, y;
        std::cin >> x >> y;
        points[i] = Point2(x, y);
    }

    return points;
}

void Print(
    const std::size_t a,
    const std::size_t b,
    const std::size_t c)
{
    std::cout << a << ' ' << b << ' ' << c;
}

int main() {
	const Points points1 = ReadPoints();

	const std::array<std::size_t, 3> indices = Solve(points1);

    Print(
        indices[0] + 1,
        indices[1] + 1,
        indices[2] + 1);
    return 0;
}


// Engineered by cnc.algo@gmail.com

// #include "solution1/FindTriangle.hpp"
//#include "solution1/Point2.hpp"
//#include "solution1/PointsIo.hpp"
#include <algorithm>
#include <array>
#include <cstddef>
#include <iostream>
#include <vector>

struct Point2
{
    Point2(
        const int x,
        const int y,
        const std::size_t i)
        : _x(x),
        _y(y),
        _i(i)
    {}

    bool operator<(const Point2& other)
    {
        if (_x < other._x) return true;
        if (_x > other._x) return false;
        if (_y < other._y) return true;
        return false;
    }

    long long _x;
    long long _y;
    std::size_t _i;
};

typedef std::vector<Point2> Points;

Points ReadPoints()
{
    std::size_t nPoints = 0;
    std::cin >> nPoints;

    Points points(nPoints, Point2(0, 0, 0));

    for (std::size_t i = 0; i < nPoints; ++i)
    {
        int x, y;
        std::cin >> x >> y;
        points[i] = Point2(x, y, i);
    }

    return points;
}

void DisplayTriangleIndices(const std::array<std::size_t, 3>& triangle)
{
    for (const auto index : triangle)
    {
        std::cout << index + 1 << ' ';
    }
    std::cout << std::endl;
}

namespace solution1
{

namespace FindTriangle
{

bool IsOnSameLine(
    const Point2& a,
    const Point2& b,
    const Point2& c)
{
    const long long signedParallelogramArea =
        (a._x - c._x) * (b._y - c._y)
        - (a._y - c._y) * (b._x - c._x);

    return signedParallelogramArea == 0;
}

std::array<std::size_t, 3> Solve(std::vector<Point2>& points)
{
    std::sort(points.begin(), points.end());

    for (std::size_t i = 2; i < points.size(); ++i)
    {
        const bool isOnSameLine = IsOnSameLine(
            points[i - 2],
            points[i - 1],
            points[i]);

        if (!isOnSameLine)
        {
            return{
                points[i - 2]._i,
                points[i - 1]._i,
                points[i]._i };
        }
    }

    throw std::runtime_error("Failed to find a valid triangle");
}

}  // namespace FindTriangle
}  // namespace solution1

int main()
{
    Points points = ReadPoints();

    const auto triangle = solution1::FindTriangle::Solve(points);

    DisplayTriangleIndices(triangle);

    return 0;
}


// Engineered by cnc.algo@gmail.com
#include <array>
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <vector>

using namespace std;

struct Point2
{
    Point2(int x_, int y_) : x(x_), y(y_) {}
int x;
int y;
};

enum half_plane_e {negative_half_plane, positive_half_plane, collinear};

half_plane_e  point_half_plane(const Point2 &px, const Point2 &p1, const Point2 &p2)
{
    std::int64_t m = (std::int64_t)(px.x - p2.x) * (std::int64_t)(p1.y - p2.y) - (std::int64_t)(p1.x - p2.x) * (std::int64_t)(px.y - p2.y);
    if (m<0)
        return negative_half_plane;
    else if (m>0)
        return positive_half_plane;
    else
        return collinear;
}

std::size_t get_left_segment_idx(const std::vector<Point2> &points, std::size_t idx_p0, std::size_t idx_p1, std::size_t idx_new){

    std::int64_t x0 = points[idx_p0].x - points[idx_new].x;
    std::int64_t y0 = points[idx_p0].y - points[idx_new].y;
    std::int64_t x1 = points[idx_p1].x - points[idx_new].x;
    std::int64_t y1 = points[idx_p1].y - points[idx_new].y;

    return ((x0*x1+y0*y1)<0) ? idx_new : idx_p1;
}

std::array<std::size_t, 3> Solve(const std::vector<Point2>& points) {
    std::size_t idx_1 = 0;
    std::size_t  idx_2 = 1;
    std::size_t  idx_3 = 0;

    for (std::size_t i = 2; i<points.size(); ++i){
        half_plane_e hp_1 = point_half_plane(points[i], points[idx_1], points[idx_2]);
        if (idx_3==0){
            if (hp_1==half_plane_e::collinear){
                idx_2 = get_left_segment_idx(points, idx_1, idx_2, i);
            }
            else{
                idx_3 = i;
            }
            continue;
        }
        half_plane_e hp_2 = point_half_plane(points[i], points[idx_2], points[idx_3]);
        if (hp_2==half_plane_e::collinear) {
            idx_3 = get_left_segment_idx(points, idx_2, idx_3, i);
            continue;
        }
        half_plane_e hp_3 = point_half_plane(points[i], points[idx_3], points[idx_1]);
        if (hp_3==half_plane_e::collinear) {
            idx_1 = get_left_segment_idx(points, idx_3, idx_1, i);
            continue;
        }

        if ((hp_1==hp_2) && (hp_2==hp_3))
            idx_3 = i;
    }
    return {idx_1, idx_2, idx_3};
}

typedef std::vector<Point2> Points;

Points ReadPoints()
{
    std::size_t nPoints = 0;
    std::cin >> nPoints;

    Points points(nPoints, Point2(0, 0));

    for (std::size_t i = 0; i < nPoints; ++i)
    {
        int x, y;
        std::cin >> x >> y;
        points[i] = Point2(x, y);
    }

    return points;
}

void DisplayPoints(const Points& points)
{
    for (const auto& point : points)
    {
        std::cout << point.x << ' ' << point.y << std::endl;
    }
}

void Print(
    const int a,
    const int b,
    const int c)
{
    std::cout << a << ' ' << b << ' ' << c;
}

int main()
{
    Points points = ReadPoints();

    std::array<std::size_t, 3> r = Solve(points);

    cout << r[0] + 1 << ' ' << r[1] + 1 << ' ' << r[2] + 1 << endl;

    return 0;
}


#include <array>
#include <iostream>
#include <vector>

typedef __int32				int32_t;
typedef unsigned __int32	uint32_t;

typedef __int64				int64_t;
typedef unsigned __int64	uint64_t;

const uint32_t MAX_COUNT = 1000000u;					// 10e6
const uint32_t MAX_COORD = 1000000000u;				// 10e9
const uint32_t MAX_DISTANCE = 0xffffffff;
const uint64_t MAX_DISTANCE2 = 0xffffffffffffffff;

struct point2i_t {

    point2i_t();
    point2i_t(int x, int y);

    point2i_t(const point2i_t& point);

    point2i_t				operator + (const point2i_t& point) const;
    point2i_t				operator - (const point2i_t& point) const;
    point2i_t				operator - () const;
    point2i_t				operator * (const point2i_t& point) const;
    point2i_t				operator / (const point2i_t& point) const;

    //point2i_t				operator / ( int n ) const;

    point2i_t&				operator += (const point2i_t& point);

    //void					assign( int x, int y );

    // ��������� ������� �����
    uint64_t				len2() const;

    // ��������� ����� ������� ���������
    uint32_t				len_up() const;

    // ��������� ������� ����������
    uint64_t				distance2(const point2i_t& point) const;

    int64_t					dot(const point2i_t& point) const;

    int32_t					m_x;
    int32_t					m_y;
};

inline
point2i_t::point2i_t() {
}

inline
point2i_t::point2i_t(int x, int y) {
    this->m_x = x;
    this->m_y = y;
}

inline
point2i_t::point2i_t(const point2i_t& point) {
    this->m_x = point.m_x;
    this->m_y = point.m_y;
}

inline
point2i_t point2i_t::operator + (const point2i_t& point) const {
    return point2i_t(
        this->m_x + point.m_x,
        this->m_y + point.m_y);
}

inline
point2i_t point2i_t::operator - (const point2i_t& point) const {
    return point2i_t(
        this->m_x - point.m_x,
        this->m_y - point.m_y);
}

inline
point2i_t point2i_t::operator - () const {
    return point2i_t(
        -this->m_x,
        -this->m_y);
}

inline
point2i_t point2i_t::operator * (const point2i_t& point) const {
    return point2i_t(
        this->m_x * point.m_x,
        this->m_y * point.m_y);
}

inline
point2i_t point2i_t::operator / (const point2i_t& point) const {
    return point2i_t(
        this->m_x / point.m_x,
        this->m_y / point.m_y);
}

//inline
//point2i_t point2i_t::operator / ( int n ) const {
//	return point2i_t(
//		this->m_x / n,
//		this->m_y / n );
//}

inline
point2i_t& point2i_t::operator += (const point2i_t& point) {
    this->m_x += point.m_x;
    this->m_y += point.m_y;
    return *this;
}

//inline
//void point2i_t::assign( int x, int y ) {
//	this->m_x = m_x;
//	this->m_y = m_y;
//}

inline
uint64_t point2i_t::len2() const {
    int64_t dx = static_cast<int64_t>(this->m_x);
    int64_t dy = static_cast<int64_t>(this->m_y);
    return static_cast<uint64_t>(dx * dx + dy * dy);
}

inline
uint32_t point2i_t::len_up() const {
    return abs(this->m_x) + abs(this->m_y);
}

inline
uint64_t point2i_t::distance2(const point2i_t& point) const {
    return (point - *this).len2();
}

inline
int64_t point2i_t::dot(const point2i_t& point) const {
    int64_t x1 = static_cast<int64_t>(this->m_x);
    int64_t y1 = static_cast<int64_t>(this->m_y);
    int64_t x2 = static_cast<int64_t>(point.m_x);
    int64_t y2 = static_cast<int64_t>(point.m_y);
    return static_cast<uint64_t>(x1 * y2 - y1 * x2);
}

struct point_id_t {

    bool				operator < (const point_id_t& point_id) const;

    uint32_t			m_index;
    uint64_t			m_distance;
};

bool point_id_t::operator < (const point_id_t& point) const {
    return (this->m_distance < point.m_distance);
}

typedef std::vector< point2i_t > points_t;

std::array< std::size_t, 3 > solve(const points_t& points) {

    const point2i_t& front_point = points.front();
    std::vector< point_id_t > points_id(points.size());

    for (std::size_t i = 0u; i < points.size(); ++i) {
        point_id_t& point_id = points_id[i];
        point_id.m_index = static_cast<uint32_t>(i);
        point_id.m_distance = front_point.distance2(points[i]);
    }
    std::sort(points_id.begin(), points_id.end());

    std::size_t n;
    const point2i_t& p1 = points[points_id[0].m_index];
    const point2i_t& p2 = points[points_id[1].m_index];
    point2i_t dv = p2 - p1;
    for (std::size_t i = 2u; i < points_id.size(); ++i) {
        if (dv.dot(points[points_id[i].m_index] - p1)) {
            n = i;
            break;
        }
    }

    std::array< std::size_t, 3 > ret;
    ret[0] = points_id[0].m_index + 1;
    ret[1] = points_id[1].m_index + 1;
    ret[2] = points_id[n].m_index + 1;
    return ret;
}

struct Point2
{
    Point2(
        const int x,
        const int y,
        const int i)
        : _x(x),
        _y(y),
        _i(i)
    {}

    bool operator<(const Point2& other)
    {
        if (_x < other._x) return true;
        if (_x > other._x) return false;
        if (_y < other._y) return true;
        return false;
    }

    long long _x;
    long long _y;
    int _i;
};

typedef std::vector<Point2> Points;

Points ReadPoints()
{
    std::size_t nPoints = 0;
    std::cin >> nPoints;

    Points points(nPoints, Point2(0, 0, 0));

    for (std::size_t i = 0; i < nPoints; ++i)
    {
        int x, y;
        std::cin >> x >> y;
        points[i] = Point2(x, y, i + 1);
    }

    return points;
}

std::array<std::size_t, 3> solve1(const Points& points)
{
    points_t copy(points.size());
    for (std::size_t i = 0; i < points.size(); ++i)
    {
        copy[i].m_x = static_cast<std::int32_t>(points[i]._x);
        copy[i].m_y = static_cast<std::int32_t>(points[i]._y);
    }

    return solve(copy);
}

int main()
{
    const auto points = ReadPoints();

    const auto solution = solve1(points);

    std::cout << solution[0] << ' ' << solution[1] << ' ' << solution[2];

    return 0;
}


#include <array>
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <vector>

struct Point2
{
    Point2(
        const int x,
        const int y,
        const int i)
    :   _x(x),
        _y(y),
        _i(i)
    {}

    bool operator<(const Point2& other)
    {
        if (_x < other._x) return true;
        if (_x > other._x) return false;
        if (_y < other._y) return true;
        return false;
    }

    long long _x;
    long long _y;
    int _i;
};

typedef std::vector<Point2> Points;

Points ReadPoints()
{
    std::size_t nPoints = 0;
    std::cin >> nPoints;

    Points points(nPoints, Point2(0, 0, 0));

    for (std::size_t i = 0; i < nPoints; ++i)
    {
        int x, y;
        std::cin >> x >> y;
        points[i] = Point2(x, y, i + 1);
    }

    return points;
}

void DisplayPoints(const Points& points)
{
    for (const auto& point : points)
    {
        std::cout << point._x << ' ' << point._y << std::endl;
    }
}

void SortPoints(Points& points)
{
    std::sort(
        points.begin(),
        points.end());
}

bool IsOnSameLine(
    const Point2& a,
    const Point2& b,
    const Point2& c)
{
    const long long signedParallelogramArea =
        (a._x - c._x) * (b._y - c._y)
        - (a._y - c._y) * (b._x - c._x);

    return signedParallelogramArea == 0;
}

void Print(
    const int a,
    const int b,
    const int c)
{
    std::cout << a << ' ' << b << ' ' << c;
}

int main()
{
    Points points = ReadPoints();

    SortPoints(points);

    for (std::size_t i = 2; i < points.size(); ++i)
    {
        const bool isOnSameLine = IsOnSameLine(
            points[i - 2],
            points[i - 1],
            points[i]);

        if (!isOnSameLine)
        {
            Print(
                points[i - 2]._i,
                points[i - 1]._i,
                points[i]._i);

            break;
        }
    }

    return 0;
}


#include <cstdlib>
#include <array>
#include <iostream>
#include <limits>
#include <vector>

const double metricEps = 1e-16;
const double metricEps2 = metricEps * metricEps;

struct Point2
{
    Point2() {};
    Point2(
        int _x,
        int _y,
        int _i)
    :   x(_x),
        y(_y),
        i(_i)
    {}

    double operator%(const Point2& point) const
    {
        return x * point.y - y * point.x;
    };

    Point2 operator-(const Point2& point) const
    {
        return Point2(x - point.x, y - point.y, i);
    }

    Point2 operator+(const Point2& point) const
    {
        return Point2(x + point.x, y + point.y, i);
    }

    double distance2(const Point2& point) const
    {
        double dx = x - point.x;
        double dy = y - point.y;
        return dx * dx + dy * dy;
    }

    int x;
    int y;
    int i;
};

struct Line2
{
    Point2 beg, end;

    double distance2(const Point2& point) const
    {
        double area = ((beg - point) % (end - point)) / 2.0;
        return area * area * 4.0 / beg.distance2(end);
    }
};

typedef std::array<std::size_t, 3> Triangle;

typedef std::vector<Point2> Cloud;

Triangle FindTriangle(const Cloud& cloud)
{
    Triangle triangle;
    triangle[0] = 0;
    triangle[1] = 1;

    Line2 line;
    line.beg = cloud[triangle[0]];
    line.end = cloud[triangle[1]];

    double minDistance2 = std::numeric_limits<double>::max();
    for (std::size_t pointId = 0; pointId < cloud.size(); pointId++)
    {
        const Point2& point = cloud[pointId];
        double distance2 = line.distance2(point);
        if (distance2 > metricEps2)
        {
            if (distance2 < minDistance2 - metricEps2)
            {
                minDistance2 = distance2;
                triangle[2] = pointId;
            }
        }
        else
        {
            double distToBeg2 = line.beg.distance2(point);
            if ((distToBeg2 > metricEps2) && (distToBeg2 < line.beg.distance2(line.end) - metricEps2))
            {
                line.end = point;
                triangle[1] = pointId;
            }
        }
    }

    return triangle;
}

Cloud ReadPoints()
{
    std::size_t nPoints = 0;
    std::cin >> nPoints;

    Cloud points(nPoints, Point2(0, 0, 0));

    for (std::size_t i = 0; i < nPoints; ++i)
    {
        int x, y;
        std::cin >> x >> y;
        points[i] = Point2(x, y, i + 1);
    }

    return points;
}

int main()
{
    Cloud cloud = ReadPoints();
    Triangle triangle = FindTriangle(cloud);

    std::cout << cloud[triangle[0]].i << ' ' << cloud[triangle[1]].i << ' ' << cloud[triangle[2]].i;

    return 0;
}


#include <cstdlib>
#include <array>
#include <iostream>
#include <limits>
#include <vector>

const double metricEps = 1e-6;
const double metricEps2 = metricEps * metricEps;

struct Point2
{
    Point2() {};
    Point2(
        int _x,
        int _y,
        int _i)
    :   x(_x),
        y(_y),
        i(_i)
    {}

    double operator%(const Point2& point) const
    {
        return x * point.y - y * point.x;
    };

    Point2 operator-(const Point2& point) const
    {
        return Point2(x - point.x, y - point.y, i);
    }

    Point2 operator+(const Point2& point) const
    {
        return Point2(x + point.x, y + point.y, i);
    }

    double distance2(const Point2& point) const
    {
        double dx = x - point.x;
        double dy = y - point.y;
        return dx * dx + dy * dy;
    }

    int x;
    int y;
    int i;
};

struct Line2
{
    Point2 beg, end;

    double distance2(const Point2& point) const
    {
        double area = ((beg - point) % (end - point)) / 2.0;
        return area * area / beg.distance2(end);
    }
};

typedef std::array<std::size_t, 3> Triangle;

typedef std::vector<Point2> Cloud;

Triangle FindTriangle(const Cloud& cloud)
{
    Triangle triangle;
    triangle[0] = 0;
    triangle[1] = 1;

    Line2 line;
    line.beg = cloud[triangle[0]];
    line.end = cloud[triangle[1]];

    double minDistance2 = std::numeric_limits<double>::max();
    for (std::size_t pointId = 0; pointId < cloud.size(); pointId++)
    {
        const Point2& point = cloud[pointId];
        double distance2 = line.distance2(point);
        if (distance2 > metricEps2)
        {
            if (distance2 < minDistance2 - metricEps2)
            {
                minDistance2 = distance2;
                triangle[2] = pointId;
            }
        }
        else
        {
            double distToBeg2 = line.beg.distance2(point);
            if ((distToBeg2 > metricEps2) && (distToBeg2 < line.beg.distance2(line.end) - metricEps2))
            {
                line.end = point;
                triangle[1] = pointId;
            }
        }
    }

    return triangle;
}

Cloud ReadPoints()
{
    std::size_t nPoints = 0;
    std::cin >> nPoints;

    Cloud points(nPoints, Point2(0, 0, 0));

    for (std::size_t i = 0; i < nPoints; ++i)
    {
        int x, y;
        std::cin >> x >> y;
        points[i] = Point2(x, y, i + 1);
    }

    return points;
}

int main()
{
    Cloud cloud = ReadPoints();
    Triangle triangle = FindTriangle(cloud);

    std::cout << cloud[triangle[0]].i << ' ' << cloud[triangle[1]].i << ' ' << cloud[triangle[2]].i;

    return 0;
}


#include <array>
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <vector>

struct Point2
{
    Point2(
        const int x,
        const int y,
        const int i)
    :   _x(x),
        _y(y),
        _i(i)
    {}

    bool operator<(const Point2& other)
    {
        if (_x < other._x) return true;
        if (_x > other._x) return false;
        if (_y < other._y) return true;
        return false;
    }

    long long _x;
    long long _y;
    int _i;
};

typedef std::vector<Point2> Points;

Points ReadPoints()
{
    std::size_t nPoints = 0;
    std::cin >> nPoints;

    Points points(nPoints, Point2(0, 0, 0));

    for (std::size_t i = 0; i < nPoints; ++i)
    {
        int x, y;
        std::cin >> x >> y;
        points[i] = Point2(x, y, i + 1);
    }

    return points;
}

void DisplayPoints(const Points& points)
{
    for (const auto& point : points)
    {
        std::cout << point._x << ' ' << point._y << std::endl;
    }
}

void SortPoints(Points& points)
{
    std::sort(
        points.begin(),
        points.end());
}

bool IsOnSameLine(
    const Point2& a,
    const Point2& b,
    const Point2& c)
{
    const long long signedParallelogramArea =
        (a._x - c._x) * (b._y - c._y)
        - (a._y - c._y) * (b._x - c._x);

    return signedParallelogramArea == 0;
}

void Print(
    const int a,
    const int b,
    const int c)
{
    std::cout << a << ' ' << b << ' ' << c;
}

int main()
{
    Points points = ReadPoints();
    SortPoints(points);

    for (std::size_t i = 2; i < points.size(); ++i)
    {
        const bool isOnSameLine = IsOnSameLine(
            points[i - 2],
            points[i - 1],
            points[i]);

        if (!isOnSameLine)
        {
            Print(
                points[i - 2]._i,
                points[i - 1]._i,
                points[i]._i);

            break;
        }
    }

    return 0;
}


// Engineered by cnc.algo@gmail.com
#include <array>
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <vector>

// Find the original problem statement here:
// http://codeforces.com/problemset/problem/618/C

//struct Point2
//{
//    Point2(
//        const int x,
//        const int y,
//        const std::size_t i)
//    :   _x(x),
//        _y(y),
//        _i(i)
//    {}
//
//    bool operator<(const Point2& other)
//    {
//        if (_x < other._x) return true;
//        if (_x > other._x) return false;
//        if (_y < other._y) return true;
//        return false;
//    }
//
//    long long _x;
//    long long _y;
//    std::size_t _i;
//};

//============================================================================================================================
struct Point2
{
    int x;
    int y;
};

//============================================================================================================================
// helper func
float calc_dist(const Point2 &a, const Point2 &b)
{
    return static_cast<float> (std::sqrt(static_cast<float>((b.x - a.x)*(b.x - a.x) + (b.y - a.y)*(b.y - a.y))));
}

typedef std::vector<Point2> Points;

Points ReadPoints()
{
    std::size_t nPoints = 0;
    std::cin >> nPoints;

    Points points(nPoints, Point2{ 0, 0 });

    for (std::size_t i = 0; i < nPoints; ++i)
    {
        int x, y;
        std::cin >> x >> y;
        points[i] = Point2{ x, y };
    }

    return points;
}

void DisplayPoints(const Points& points)
{
    for (const auto& point : points)
    {
        std::cout << point.x << ' ' << point.y << std::endl;
    }
}

//void SortPoints(Points& points)
//{
//    std::sort(
//        points.begin(),
//        points.end());
//}

//bool IsOnSameLine(
//    const Point2& a,
//    const Point2& b,
//    const Point2& c)
//{
//    const long long signedParallelogramArea =
//        (a._x - c._x) * (b._y - c._y)
//        - (a._y - c._y) * (b._x - c._x);
//
//    return signedParallelogramArea == 0;
//}

void Print(
    const std::size_t a,
    const std::size_t b,
    const std::size_t c)
{
    std::cout << a << ' ' << b << ' ' << c;
}

std::array<std::size_t, 3> Solve(const std::vector<Point2>& points)
{
    // Well, I need 3 points for triangle
    int pA_index = 0;
    int pB_index = 1;
    int pC_index = 0;

    // Let's take some point from points, 1-st for example
    Point2 pA = points.at(pA_index); // can use operator =, 'cuz it's trivial by defauult for Point2 struct.

                                     // Let's take another some point from points, 2-nd for example
    Point2 pB = points.at(pB_index);

    // The distance beween this points is
    float d_AB = calc_dist(pA, pB);

    // The minimum sides length triangle ABC will not contains the other points inside. So just find the minimum AC and BC sides.
    // It's obviously, that minimum AC and BC sides is for minimum pN.x && pN.y for d_AC and d_BC sides. Let's do it.

    //Point2 pMin = { pow(10.0f, 9), pow(10.0f, 9) };

    float d_AC_BC_min = static_cast<float>(pow(2 * 10.0f, 9)); // minimum AC + BC length. Initiated with maximum distance 2*1e9

    for (int i = 1; i < points.size(); ++i) {

        Point2 pC = points.at(i);
        float d_AC = calc_dist(pA, pC);
        float d_BC = calc_dist(pB, pC);

        float d_AC_BC = d_AC + d_BC;

        if (d_AC != 0 && d_BC != 0 && d_AC_BC != d_AB && d_AC_BC < d_AC_BC_min)
        {
            d_AC_BC_min = d_AC + d_BC;
            pC_index = i;
        }
    }

    std::array<std::size_t, 3> arr = { pA_index, pB_index, pC_index };

    return arr;
}

int main()
{
    Points points = ReadPoints();

    const auto solve = Solve(points);

    std::cout << solve[0] + 1 << ' ' << solve[1] + 1 << ' ' << solve[2] + 1 << std::endl;

    return 0;
}


#include <iostream>
#include <array>
#include <vector>
#include <list>
#include <cmath>
#include <algorithm>

struct Point2
{
    int x;
    int y;
};

typedef std::vector<Point2> Points;

std::vector<Point2> test_points ={  {-9, 5},
                                    {-8,-2},
                                    {-4,-3},
                                    {-2, 2},
                                    {-3,-4},
                                    {-1,-1},
                                    {-1, 1},
                                    { 1,-5},
                                    { 1, 9},
                                    { 3,-8},
                                    { 3, 5},
                                    { 5,-2},
                                    { 9,-3},
                                    { 9, 3}
                                };

void InitRandomTestData()
{
    Point2 p;

    for (unsigned int i = 0; i < 100; i++)
    {
        p.x = std::rand() % 2001 - 1000;
        p.y = std::rand() % 2001 - 1000;
        test_points.push_back(p);
    }
}

inline float length(const Point2 & A, const Point2 & B)
{
    return std::sqrt((A.x - B.x + .0)*(A.x - B.x + .0) + (A.y - B.y + .0)*(A.y - B.y + .0) + .0);
}

inline float area(const Point2 & A, const Point2 & B, const Point2 & C)
{
    return std::abs(.5 * ((A.x - C.x + .0)*(B.y - C.y + .0) - (B.x - C.x + .0)*(A.y - C.y + .0) + .0));
}

inline bool compareX(const Point2 & A, const Point2 & B)
{
	return A.x < B.x || (A.x == B.x && A.y < B.y);
}

inline bool compareY(const Point2 & A, const Point2 & B)
{
	return A.y < B.y;
}

std::array<std::size_t, 3> Solve(const std::vector<Point2>& points)
{
    unsigned int a = 0;
    unsigned int b = 1;
    unsigned int c = 2;
    float s, s1, s2, s3;

    if (3 == points.size())
        return {a, b, c};

    for (unsigned int i = 3; i < points.size(); ++i)
    {
        if (0. != area(points[a], points[b], points[c]))
            break;
        c = i;
    }

    s = area(points[a], points[b], points[c]);
    for (unsigned int i = 2; i < points.size(); ++i)
    {
        s1 = area(points[i], points[b], points[c]);
        s2 = area(points[a], points[i], points[c]);
        s3 = area(points[a], points[b], points[i]);

        if ( s < s1 + s2 + s3 )
            continue;

        if (0. == s1)
            c = i;
        else if (0. == s2)
            c = i;
        else if (0. == s3)
            a = i;
        else if (s1 + s2 + s3 == s)
            b = i;

        s = area(points[a], points[b], points[c]);
    }

    return {a, b, c};
}

float RecFindMinDistance(std::vector<Point2>& points)
{
    float len = 3e9;
    float tmpLen = 3e9;

    if (1 >= points.size())
        return len;

    if (2 == points.size())
    {
        std::sort(points.begin(), points.end(), &compareY);

        return length(points[0], points[1]);
    }

    unsigned int mid = points.size() / 2;
    std::vector<Point2> leftPoints(points.begin(), points.begin() + mid);
    std::vector<Point2> rightPoints(points.begin() + mid, points.end());

    len = RecFindMinDistance(leftPoints);
    if (len > (tmpLen = RecFindMinDistance(rightPoints)))
        len = tmpLen;

    std::merge(leftPoints.begin(), leftPoints.end(), rightPoints.begin(), rightPoints.end(), points.begin(), &compareY);

    std::list<Point2> tmpPoints;

    for (std::vector<Point2>::const_iterator it = points.begin(); it != points.end(); ++it)
        if (std::abs(it->x - points[mid].x) < len)
        {
            for (std::list<Point2>::iterator jt = tmpPoints.begin(); jt != tmpPoints.end() && (it->y - jt->y < len); ++jt)
                if (len > (tmpLen = length(*it, *jt)))
                    len = tmpLen;
            tmpPoints.push_front(*it);
        }

    return len;
}

float FindMinDistance(const std::vector<Point2>& points)
{
    std::vector<Point2> sortedPoints(points);

    std::sort(sortedPoints.begin(), sortedPoints.end(), &compareX);

    return RecFindMinDistance(sortedPoints);
}

Points ReadPoints()
{
    std::size_t nPoints = 0;
    std::cin >> nPoints;

    Points points(nPoints, Point2{ 0, 0 });

    for (std::size_t i = 0; i < nPoints; ++i)
    {
        int x, y;
        std::cin >> x >> y;
        points[i] = Point2{ x, y };
    }

    return points;
}

int main()
{
    Points points = ReadPoints();
    auto solution1 = Solve(test_points);

    std::cout << solution1[0] + 1 << ' ' << solution1[1] + 1 << ' ' << solution1[2] + 1 << std::endl;

 //   std::array<std::size_t, 3> res1;
 //   float res2;

 ////   InitRandomTestData();

 //   for (std::vector<Point2>::iterator it = test_points.begin(); it != test_points.end(); ++it)
 //       std::cout << it->x << " " << it->y << std::endl;

 //   std::cout << "---" << std::endl;

 //   res1 = Solve(test_points);
 //   res2 = FindMinDistance(test_points);

 //   std::cout << res1[0] << " " << res1[1] << " " << res1[2] << std::endl;
 //   std::cout << res2 << std::endl;

    return 0;
}


#include <array>
#include <cstdlib>
#include <iostream>
#include <vector>

typedef __int32				int32_t;
typedef unsigned __int32	uint32_t;

typedef __int64				int64_t;
typedef unsigned __int64	uint64_t;

const uint32_t MAX_COUNT = 1000000u;					// 10e6
const uint32_t MAX_COORD = 1000000000u;				// 10e9
const uint32_t MAX_DISTANCE = 0xffffffff;
const uint64_t MAX_DISTANCE2 = 0xffffffffffffffff;

struct point2i_t {

    point2i_t();
    point2i_t(int x, int y);

    point2i_t(const point2i_t& point);

    point2i_t				operator + (const point2i_t& point) const;
    point2i_t				operator - (const point2i_t& point) const;
    point2i_t				operator - () const;
    point2i_t				operator * (const point2i_t& point) const;
    point2i_t				operator / (const point2i_t& point) const;

    //point2i_t				operator / ( int n ) const;

    point2i_t&				operator += (const point2i_t& point);

    //void					assign( int x, int y );

    // ��������� ������� �����
    uint64_t				len2() const;

    // ��������� ����� ������� ���������
    uint32_t				len_up() const;

    // ��������� ������� ����������
    uint64_t				distance2(const point2i_t& point) const;

    int64_t					dot(const point2i_t& point) const;

    int32_t					m_x;
    int32_t					m_y;
};

inline
point2i_t::point2i_t() {
}

inline
point2i_t::point2i_t(int x, int y) {
    this->m_x = x;
    this->m_y = y;
}

inline
point2i_t::point2i_t(const point2i_t& point) {
    this->m_x = point.m_x;
    this->m_y = point.m_y;
}

inline
point2i_t point2i_t::operator + (const point2i_t& point) const {
    return point2i_t(
        this->m_x + point.m_x,
        this->m_y + point.m_y);
}

inline
point2i_t point2i_t::operator - (const point2i_t& point) const {
    return point2i_t(
        this->m_x - point.m_x,
        this->m_y - point.m_y);
}

inline
point2i_t point2i_t::operator - () const {
    return point2i_t(
        -this->m_x,
        -this->m_y);
}

inline
point2i_t point2i_t::operator * (const point2i_t& point) const {
    return point2i_t(
        this->m_x * point.m_x,
        this->m_y * point.m_y);
}

inline
point2i_t point2i_t::operator / (const point2i_t& point) const {
    return point2i_t(
        this->m_x / point.m_x,
        this->m_y / point.m_y);
}

//inline
//point2i_t point2i_t::operator / ( int n ) const {
//	return point2i_t(
//		this->m_x / n,
//		this->m_y / n );
//}

inline
point2i_t& point2i_t::operator += (const point2i_t& point) {
    this->m_x += point.m_x;
    this->m_y += point.m_y;
    return *this;
}

//inline
//void point2i_t::assign( int x, int y ) {
//	this->m_x = m_x;
//	this->m_y = m_y;
//}

inline
uint64_t point2i_t::len2() const {
    int64_t dx = static_cast<int64_t>(this->m_x);
    int64_t dy = static_cast<int64_t>(this->m_y);
    return static_cast<uint64_t>(dx * dx + dy * dy);
}

inline
uint32_t point2i_t::len_up() const {
    return abs(this->m_x) + abs(this->m_y);
}

inline
uint64_t point2i_t::distance2(const point2i_t& point) const {
    return (point - *this).len2();
}

inline
int64_t point2i_t::dot(const point2i_t& point) const {
    int64_t x1 = static_cast<int64_t>(this->m_x);
    int64_t y1 = static_cast<int64_t>(this->m_y);
    int64_t x2 = static_cast<int64_t>(point.m_x);
    int64_t y2 = static_cast<int64_t>(point.m_y);
    return static_cast<uint64_t>(x1 * y2 - y1 * x2);
}

struct point_id_t {

    bool				operator < (const point_id_t& point_id) const;

    uint32_t			m_index;
    uint64_t			m_distance;
};

bool point_id_t::operator < (const point_id_t& point) const {
    return (this->m_distance < point.m_distance);
}

typedef std::vector< point2i_t > points_t;

std::array< std::size_t, 3 > solve(const points_t& points) {

    const point2i_t& front_point = points.front();
    std::vector< point_id_t > points_id(points.size());

    for (std::size_t i = 0u; i < points.size(); ++i) {
        point_id_t& point_id = points_id[i];
        point_id.m_index = static_cast<uint32_t>(i);
        point_id.m_distance = front_point.distance2(points[i]);
    }
    std::sort(points_id.begin(), points_id.end());

    std::size_t n;
    const point2i_t& p1 = points[points_id[0].m_index];
    const point2i_t& p2 = points[points_id[1].m_index];
    point2i_t dv = p2 - p1;
    for (std::size_t i = 2u; i < points_id.size(); ++i) {
        if (dv.dot(points[points_id[i].m_index] - p1)) {
            n = i;
            break;
        }
    }

    std::array< std::size_t, 3 > ret;
    ret[0] = points_id[0].m_index + 1;
    ret[1] = points_id[1].m_index + 1;
    ret[2] = points_id[n].m_index + 1;
    return ret;
}

struct Point2
{
    Point2(
        const int x,
        const int y,
        const int i)
        : _x(x),
        _y(y),
        _i(i)
    {}

    bool operator<(const Point2& other)
    {
        if (_x < other._x) return true;
        if (_x > other._x) return false;
        if (_y < other._y) return true;
        return false;
    }

    long long _x;
    long long _y;
    int _i;
};

typedef std::vector<Point2> Points;

Points ReadPoints()
{
    std::size_t nPoints = 0;
    std::cin >> nPoints;

    Points points(nPoints, Point2(0, 0, 0));

    for (std::size_t i = 0; i < nPoints; ++i)
    {
        int x, y;
        std::cin >> x >> y;
        points[i] = Point2(x, y, i + 1);
    }

    return points;
}

std::array<std::size_t, 3> solve1(const Points& points)
{
    points_t copy(points.size());
    for (std::size_t i = 0; i < points.size(); ++i)
    {
        copy[i].m_x = static_cast<std::int32_t>(points[i]._x);
        copy[i].m_y = static_cast<std::int32_t>(points[i]._y);
    }

    return solve(copy);
}

int main()
{
    const auto points = ReadPoints();

    const auto solution = solve1(points);

    std::cout << solution[0] << ' ' << solution[1] << ' ' << solution[2];

    return 0;
}


// Engineered by cnc.algo@gmail.com
#include <array>
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <vector>

struct Point2 {
    int x;
    int y;
};

//struct Point2
//{
//    Point2(
//        const int x,
//        const int y,
//        const int i)
//    :   _x(x),
//        _y(y),
//        _i(i)
//    {}
//
//    bool operator<(const Point2& other)
//    {
//        if (_x < other._x) return true;
//        if (_x > other._x) return false;
//        if (_y < other._y) return true;
//        return false;
//    }
//
//    long long _x;
//    long long _y;
//    int _i;
//};

typedef std::vector<Point2> Points;

Points ReadPoints()
{
    std::size_t nPoints = 0;
    std::cin >> nPoints;

    Points points(nPoints, { 0, 0 });

    for (std::size_t i = 0; i < nPoints; ++i)
    {
        int x, y;
        std::cin >> x >> y;
        points[i] = { x, y };
    }

    return points;
}

//void DisplayPoints(const Points& points)
//{
//    for (const auto& point : points)
//    {
//        std::cout << point._x << ' ' << point._y << std::endl;
//    }
//}

//void SortPoints(Points& points)
//{
//    std::sort(
//        points.begin(),
//        points.end());
//}

//bool IsOnSameLine(
//    const Point2& a,
//    const Point2& b,
//    const Point2& c)
//{
//    const long long signedParallelogramArea =
//        (a._x - c._x) * (b._y - c._y)
//        - (a._y - c._y) * (b._x - c._x);
//
//    return signedParallelogramArea == 0;
//}

void Print(
    const int a,
    const int b,
    const int c)
{
    std::cout << a << ' ' << b << ' ' << c;
}

void sortRiseX(std::vector<Point2> &out) {
    std::sort(out.begin(), out.end(), [](Point2 &pt1, Point2 &pt2) {
        return pt1.x < pt2.x;
    });
}

void sortRiseX(std::vector<std::pair<int,Point2>> &out) {
    std::sort(out.begin(), out.end(), [](std::pair<int,Point2> &pt1, std::pair<int,Point2> &pt2) {
        return pt1.second.x < pt2.second.x;
    });
}

constexpr bool isCollinear(const Point2 &a, const Point2 &b, const Point2 &c) {
    return (a.y - b.y) * (a.x - c.x) == (a.y - c.y) * (a.x - b.x);
}

std::array<std::size_t, 3> Solve(const std::vector<Point2>& points)
{
// Solution.
    std::array<std::size_t, 3> ret{0,0,0};
    if(points.size() < 3) {
        return ret;
    }
    std::vector<std::pair<int,Point2>> sorted_points;
    for(auto i = 0u; i < points.size(); i++) {
        sorted_points.push_back({i,points[i]});
    }
    sortRiseX(sorted_points);
    for(auto i = 0u; i < sorted_points.size() - 2; i++) {
        ret[0] = sorted_points[i].first;
        ret[1] = sorted_points[i+1].first;
        ret[2] = sorted_points[i+2].first;
        if(!isCollinear(sorted_points[i].second, sorted_points[i+1].second, sorted_points[i+2].second)) {
            return ret;
        }
    }

    return {0,0,0};
}

int main()
{
    Points points = ReadPoints();
    const auto result = Solve(points);
    Print(
        result[0] + 1,
        result[1] + 1,
        result[2] + 1);

    //SortPoints(points);

    //for (std::size_t i = 2; i < points.size(); ++i)
    //{
    //    const bool isOnSameLine = IsOnSameLine(
    //        points[i - 2],
    //        points[i - 1],
    //        points[i]);

    //    if (!isOnSameLine)
    //    {
    //        Print(
    //            points[i - 2]._i,
    //            points[i - 1]._i,
    //            points[i]._i);

    //        break;
    //    }
    //}

    return 0;
}


#include <array>
#include <vector>
#include <algorithm>
#include <iostream>

//---------------------------------------------------------------------------------------------------------------------

struct Point2 {
    Point2(int xx, int yy) : x(xx), y(yy) {}
    Point2() = default;

	int x;
	int y;
};

int compare_x_coord(const void* p1, const void* p2) {
	return reinterpret_cast<const Point2*>(p1)->x - reinterpret_cast<const Point2*>(p2)->x;
}

int compare_y_coord(const void* p1, const void* p2) {
	return reinterpret_cast<const Point2*>(p1)->y - reinterpret_cast<const Point2*>(p2)->y;
}

/*---------------------------------------------------Задача 1----------------------------------------------------------
В заданном облаке точек на плоскости (каждая точка определяется двумя целочисленными координатами: x, y) найти 3 любые точки,
которые образуют невырожденный треугольник (имеющий ненулевую площадь). Все остальные точки должны находиться строго за пределами этого треугольника.
Заданные точки не принадлежат одной прямой.
Никакие две точки не находятся в одной позиции.
Количество точек может быть от 3 до 1е5.
Каждая из заданных координат может находиться в пределах от -1е9 до 1е9.
Метод Solve() принимает облако точек, заданных в плоскости, и возвращает 3 индекса точек из заданного облака,
удовлетворяющих решению поставленной задачи.*/

struct Point2_Index : Point2 {
	size_t index;
};

inline bool PointsOnTheLine(const Point2& p1, const Point2& p2, const Point2& p3)  {
	return  static_cast<__int64>(p2.x-p1.x) * (p3.y-p1.y)  -  static_cast<__int64>(p3.x-p1.x) * (p2.y-p1.y)  ==  0;
}

std::array<std::size_t, 3> Solve(const std::vector<Point2>& points) {
	std::array<std::size_t, 3> result = {-1, -1, -1}; // initialize with invalid indices
	std::vector<Point2_Index> points_indices(points.size());
	size_t i;
	for(i=0; i<points_indices.size(); i++) { // copy unsorted points and create successive indices
		points_indices[i].x = points[i].x;
		points_indices[i].y = points[i].y;
		points_indices[i].index = i;
	}
	std::qsort(&points_indices[0], points_indices.size(), sizeof(Point2_Index), compare_x_coord); // order by ascending x coordinate.

	auto p1 = points_indices.begin(), // first point
		 p2 = p1+1; // second point

	if(p2->x == p1->x) { // 2 (or more) points with the same x coordinate=p1.x
		p2++; // p2=3rd point
		while(p2 != points_indices.end()  &&  p2->x == p1->x) p2++; // find the end of the range with x coordinate=p1.x. the end will be assigned to p2
		if(p2 == points_indices.end()) return result; // bad input. all points are on the same line X=p1.x
		i = std::distance(p1, p2); // save i - index of the first element p2: p2.x!=p1.x
		std::qsort(std::addressof(*p1), i, sizeof(Point2_Index), compare_y_coord); // order subset {x coordinate=p1.x} by ascending y coordinate.
		result[0] = points_indices[0].index; // 2 first points with the same x coordinate=p1.x and ascending y coordinates
		result[1] = points_indices[1].index;
		result[2] = points_indices[i].index; // a point with a different x coordinate=p2.x
	}

	else { // 2 points with different x coordinates
		auto p3 = p2+1; // p3=3rd point
		do {

			while(p3 != points_indices.end()  &&  p3->x == p2->x) p3++; // find the end of the range with x coordinate=p2.x. the end will be assigned to p3

			if(std::distance(p2, p3) > 1) { // there are 2 (or more) points in subset {x coordinate=p2.x}
				i=std::distance(p1, p2); // save p2 iterator index before sorting
				std::qsort(std::addressof(*p2), std::distance(p2, p3), sizeof(Point2_Index), compare_y_coord); // order subset {x coordinate=p2.x} by ascending y coordinate
				p2 = points_indices.begin() + i; // restore p2 iterator index after sorting
				p3 = p2 + 1; // restore p3 iterator index after sorting
				break;
				/* output will be:
				result[0] = p1->index; // p1.x
				result[1] = p2->index; // p2.x<p1.x, p2.y==max_y
				result[2] = (p2+1)->index; // p3.x==p2.x, p3.y==previous(max_y)
				return result;
				*/
			}

			// else there is only 1 point with x coordinate=p2.x
			if(!PointsOnTheLine(*p1, *p2, *p3)) { // luck! (p1,p2,p3) are not on the same line
				break;
				/* output will be:
				result[0] = p1->index; // p1.x
				result[1] = p2->index; // p2.x<p1.x
				result[2] = p3->index; // p3.x<p2.x and (p1,p2,p3) are not on the same line
				return result;
				*/
			}

			// else (p1,p2,p3) are on the same line. consider p1=p2, p2=p3, p3=p2+1 and run check again
			p1 = p2;
			p2 = p3;
			p3 = p2+1;

		} while(true);
		result[0] = p1->index;
		result[1] = p2->index;
		result[2] = p3->index;
	}

	return result;
}

/*---------------------------------------------------Задача 2----------------------------------------------------------
В заданном облаке точек на плоскости (каждая точка определяется двумя целочисленными координатами: x, y) найти пару точек
с кратчайшим расстоянием между друг другом среди всех пар точек.
Количество точек может быть от 2 до 1е6.
Каждая из заданных координат может находиться в пределах от -1е9 до 1е9.
Метод FindMinDistance() принимает облако точек, заданных в плоскости, и возвращает дистанцию между двумя ближайшими точками в заданном облаке. */

inline __int64 distance2(const Point2& a, const Point2& b) {
	int dx = a.x-b.x, dy = a.y-b.y;
	return static_cast<__int64>(dx)*dx + static_cast<__int64>(dy)*dy; // square of distance
}

__int64 find_min_distance2_brute(const std::vector<Point2>& points) { // find minimal square of distance - brute
	__int64 d2,
			min_d2 = 8000000000000000000; // set current min square to max possible value: 2e9^2 + 2e9^2
	for(auto i = points.begin(); i < points.end()-1; i++)
		for(auto j = i+1; j < points.end(); j++) {
			d2=distance2(*i, *j);
			if(d2 < min_d2) {
				if(d2 == 1) return 1; // luck, found min possible distance in given space
				min_d2 = d2;
			}
		}
	return min_d2;
}

__int64 find_min_distance2(const std::vector<Point2>& point_sorted_x, const std::vector<Point2>& point_sorted_y) { // find minimal square of distance - smart
	if(point_sorted_x.size() <= 3)	return find_min_distance2_brute(point_sorted_x);

	size_t im = point_sorted_x.size()/2; // median point index
	const int xm = point_sorted_x[im].x; // x coordinate of a median point
	std::vector<Point2> points_left_subset_sorted_x, points_left_subset_sorted_y, // here we will put points with x <= point[im].x, one subset ordered by x, one by y
						points_right_subset_sorted_x, points_right_subset_sorted_y, // here we will put points with x > point[im].x, one subset ordered by x, one by y
						points_stripe_subset_sorted_y; // here we will put points p: |p.x-xm|<some distance value. this subset is ordered by y

	// fill the left and right subsets:
	std::copy(std::begin(point_sorted_x), std::begin(point_sorted_x) + im, std::back_inserter(points_left_subset_sorted_x));
	std::copy(std::begin(point_sorted_x) + im, std::end(point_sorted_x), std::back_inserter(points_right_subset_sorted_x));
	std::copy_if(std::begin(point_sorted_y), std::end(point_sorted_y), std::back_inserter(points_left_subset_sorted_y),
		[&xm](const Point2& p) {	return p.x <= xm;	});
	std::copy_if(std::begin(point_sorted_y), std::end(point_sorted_y), std::back_inserter(points_right_subset_sorted_y),
		[&xm](const Point2& p) {	return p.x > xm;	});

	// find minimal square of distance in left subset, right subset and choose minimum of those 2 values:
	__int64 min_d2_left = find_min_distance2(points_left_subset_sorted_x, points_left_subset_sorted_y),
			min_d2_right = find_min_distance2(points_right_subset_sorted_x, points_right_subset_sorted_y),
			min_d2 = min_d2_right <= min_d2_left ? min_d2_right : min_d2_left;

	if(min_d2 == 1) return 1; // luck, found min possible distance in given space

	float min_d = sqrtf(static_cast<float>(min_d2)); // min distance

	// fill stripe subset:
	std::copy_if(std::begin(point_sorted_y), std::end(point_sorted_y), std::back_inserter(points_stripe_subset_sorted_y),
		[&xm, &min_d](const Point2& p) { return abs(xm-p.x) < min_d; });

	// analyze stripe subset for feasible closest points:
	for(auto i = points_stripe_subset_sorted_y.begin(); i < points_stripe_subset_sorted_y.end()-1; i++)
		for(auto j = i+1; j<points_stripe_subset_sorted_y.end(); j++) {
			if(abs(j->y-i->y) >= min_d) break; /* points i and j are not qualified as feasible closest candidates
												  because y-distance is further than found min distance, proceed with next i index */
			__int64 d2 = distance2(*i, *j); // square of distance between points i and j
			if(d2 < min_d2) {
				if(d2 == 1) return 1; // luck, found min possible distance in given space
				min_d2 = d2;
				min_d = sqrtf(static_cast<float>(min_d2));
			}
		}

	return min_d2;
}

float FindMinDistance(const std::vector<Point2>& points) {
	auto point_sorted_x(points), point_sorted_y(points);
	std::qsort(&point_sorted_x[0], point_sorted_x.size(), sizeof(Point2), compare_x_coord);
	std::qsort(&point_sorted_y[0], point_sorted_y.size(), sizeof(Point2), compare_y_coord);
	return sqrtf(static_cast<float>(find_min_distance2(point_sorted_x, point_sorted_y)));
}
//---------------------------------------------------------------------------------------------------------------------

typedef std::vector<Point2> Points;

Points ReadPoints()
{
    std::size_t nPoints = 0;
    std::cin >> nPoints;

    Points points(nPoints, Point2(0, 0));

    for (std::size_t i = 0; i < nPoints; ++i)
    {
        int x, y;
        std::cin >> x >> y;
        points[i] = Point2(x, y);
    }

    return points;
}

void Print(
    const std::size_t a,
    const std::size_t b,
    const std::size_t c)
{
    std::cout << a << ' ' << b << ' ' << c;
}

void main() {
	const Points points1 = ReadPoints();

	const std::array<std::size_t, 3> indices = Solve(points1);

    Print(
        indices[0] + 1,
        indices[1] + 1,
        indices[2] + 1);
}


#include <array>
#include <iostream>
#include <vector>

const double metricEps = 1e-6;
const double metricEps2 = metricEps*metricEps;

struct Point2
{
    int x, y, i;

    Point2() {};
    Point2(int _x, int _y, int _i) : x(_x), y(_y), i(_i) {};

    double operator* (const Point2& point) const { return x*point.x + y*point.y; };
    double operator% (const Point2& point) const { return x*point.y - y*point.x; };
    Point2 operator- (const Point2& point) const { return Point2(x - point.x, y - point.y, i); };
    Point2 operator+ (const Point2& point) const { return Point2(x + point.x, y + point.y, i); };

    double distance2(const Point2& point) const { double dx = x - point.x, dy = y - point.y; return dx*dx + dy*dy; }
};

struct Line2
{
    Point2 beg, end;

    double distance2(const Point2& point) const { double area = ((beg - point) % (end - point)) / 2.0; return area*area / beg.distance2(end); };
};

typedef std::array<std::size_t, 3> Triangle;

typedef std::vector<Point2> Cloud;

Triangle FindTriangle(const Cloud& cloud)
{
    Triangle triangle;
    triangle[0] = 0;
    triangle[1] = 1;

    Line2 line;
    line.beg = cloud[triangle[0]];
    line.end = cloud[triangle[1]];

    double minDistance2 = std::numeric_limits<double>::max();
    for (size_t pointId = 0; pointId < cloud.size(); pointId++)
    {
        const Point2& point = cloud[pointId];
        double distance2 = line.distance2(point);
        if (distance2 > metricEps2)
        {
            if (distance2 < minDistance2 - metricEps2)
            {
                minDistance2 = distance2;
                triangle[2] = pointId;
            }
        }
        else
        {
            double distToBeg2 = line.beg.distance2(point);
            if ((distToBeg2 > metricEps2) && (distToBeg2 < line.beg.distance2(line.end) - metricEps2))
            {
                line.end = point;
                triangle[1] = pointId;
            }
        }
    }

    return triangle;
}

Cloud ReadPoints()
{
    std::size_t nPoints = 0;
    std::cin >> nPoints;

    Cloud points(nPoints, Point2(0, 0, 0));

    for (std::size_t i = 0; i < nPoints; ++i)
    {
        int x, y;
        std::cin >> x >> y;
        points[i] = Point2(x, y, i + 1);
    }

    return points;
}

int main()
{
    Cloud cloud = ReadPoints();
    Triangle triangle = FindTriangle(cloud);

    std::cout << cloud[triangle[0]].i << ' ' << cloud[triangle[1]].i << ' ' << cloud[triangle[2]].i;

    return 1;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <functional>
#include <array>

struct Point2
{
	int x;
	int y;
};

std::array<std::size_t, 3> Solve(const std::vector<Point2>& points)
{
	std::vector<Point2> cppoints(points);
	std::vector<Point2> tp(cppoints.begin(), cppoints.begin()+1);
	std::array<std::size_t, 3> arrres;

	arrres[0] = 0;

	int cnt = 1;
	int max;
	long long len[2];
	std::for_each(cppoints.begin() + 1, cppoints.end(), [&](Point2 f){
		switch(tp.size()){
			case 1:
				if((tp[0].x != f.x)||(tp[0].y != f.y)){
					tp.push_back(f);
					arrres[1] = cnt;
				} break;
			case 2:
			if((tp[0].x != f.x)||(tp[0].y != f.y)){
				if(tp[1].x * f.y != tp[1].y * f.x){
					tp.push_back(f);
					len[0] = (long long)(tp[1].x - tp[0].x)*(tp[1].x - tp[0].x) + (long long)(tp[1].y - tp[0].y)*(tp[1].y - tp[0].y);
					len[1] = (long long)(tp[2].x - tp[0].x)*(tp[2].x - tp[0].x) + (long long)(tp[2].y - tp[0].y)*(tp[2].y - tp[0].y);
					max = (len[0] > len[1])? 0:1;
					arrres[2] = cnt;
				}
			} break;
			case 3:
			//std::cout<<f.x<<","<<f.y<<std::endl;
			if((tp[0].x != f.x)||(tp[0].y != f.y)){
				int idx;
				if(len[0] != len[1]){
					if(tp[!max + 1].x * f.y != tp[!max + 1].y * f.x) idx = max;
					else idx = !max;
				}
				else{
					if(tp[!0 + 1].x * f.y != tp[!0 + 1].y * f.x) idx = 0;
					else if(tp[!1 + 1].x * f.y != tp[!1 + 1].y * f.x) idx = 1;
				}

				long long lennext = (long long)(f.x - tp[0].x)*(f.x - tp[0].x) + (long long)(f.y - tp[0].y)*(f.y - tp[0].y);
				if(lennext < len[idx]){
					tp[idx+1].x = f.x;
					tp[idx+1].y = f.y;
					len[idx] = lennext;
					max = (len[0] > len[1])? 0:1;
					arrres[idx+1] = cnt;
				}
			} break;
			default: break;
		}
		cnt++;
	});

	return arrres;
}

std::vector<Point2> ReadPoints()
{
    std::size_t nPoints = 0;
    std::cin >> nPoints;

    std::vector<Point2> points;//  (nPoints, Point2(0, 0, 0));

    for (std::size_t i = 0; i < nPoints; ++i)
    {
        int x, y;
        std::cin >> x >> y;
        points.push_back({ x, y });
    }

    return points;
}

int main()
{
    std::vector<Point2> input = ReadPoints(); //  { {0, 0}, { 1, 2 }, { 3, 1 }, { 1, 1 }, { 2, 1 }, { 4, 1 } };
    auto out = Solve(input);
    for (auto a : out)
        std::cout << a + 1 << ' ';

    return 0;
}


#include <array>
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <vector>

struct Point2
{
    Point2(
        const int x,
        const int y,
        const int i)
    :   _x(x),
        _y(y),
        _i(i)
    {}

    bool operator<(const Point2& other)
    {
        if (_x < other._x) return true;
        if (_x > other._x) return false;
        if (_y < other._y) return true;
        return false;
    }

    int _x;
    int _y;
    int _i;
};

typedef std::vector<Point2> Points;

Points ReadPoints()
{
    std::size_t nPoints = 0;
    std::cin >> nPoints;

    Points points(nPoints, Point2(0, 0, 0));

    for (std::size_t i = 0; i < nPoints; ++i)
    {
        int x, y;
        std::cin >> x >> y;
        points[i] = Point2(x, y, i + 1);
    }

    return points;
}

void DisplayPoints(const Points& points)
{
    for (const auto& point : points)
    {
        std::cout << point._x << ' ' << point._y << std::endl;
    }
}

void SortPoints(Points& points)
{
    std::sort(
        points.begin(),
        points.end());
}

bool IsOnSameLine(
    const Point2& a,
    const Point2& b,
    const Point2& c)
{
    const long long signedParallelogramArea =
        (a._x - c._x) * (b._y - c._y)
        - (a._y - c._y) * (b._x - c._x);

    return signedParallelogramArea == 0;
}

void Print(
    const int a,
    const int b,
    const int c)
{
    std::cout << a << ' ' << b << ' ' << c << std::endl;
}

int main()
{
    Points points = ReadPoints();
    SortPoints(points);

    for (std::size_t i = 2; i < points.size(); ++i)
    {
        const bool isOnSameLine = IsOnSameLine(
            points[i - 2],
            points[i - 1],
            points[i]);

        if (!isOnSameLine)
        {
            Print(
                points[i - 2]._i,
                points[i - 1]._i,
                points[i]._i);

            break;
        }
    }

    return 0;
}


#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <list>
#include <vector>
#include <utility>
#include <queue>
#include <cmath>
#include <cstdint>
#include <set>
#include <algorithm>
#include <unordered_map>

using namespace std;

#define t32 (uint32_t)
#define t64 (uint64_t)

template<int MAX_SIZE>
class bigInt {

   uint32_t pInt[MAX_SIZE];
   int32_t size;
   int8_t sign;

   static inline char abscomp(const bigInt& lhs, const bigInt& rhs) {
      if (lhs.size < rhs.size) return 1;
      if (lhs.size > rhs.size) return -1;
      for (int i = lhs.size - 1; i >= 0; --i) {
         if (lhs.pInt[i] < rhs.pInt[i]) return 1;
         if (lhs.pInt[i] > rhs.pInt[i]) return -1;
      }
      return 0;
   }

public:

   inline bigInt() {
      memset(pInt, 0, MAX_SIZE * sizeof(decltype(pInt[0])));
      size = 0;
      sign = 1;
   }

   inline bigInt(int64_t x) {
      *this = x;
   }

   inline bigInt(const bigInt& x) {
      *this = x;
   }

   inline bigInt& operator=(const bigInt& x) {
      memcpy(this, &x, sizeof(bigInt));
      return *this;
   }

   inline bigInt& operator=(int64_t x) {
      memset(pInt, 0, MAX_SIZE * sizeof(decltype(pInt[0])));
      if (x < 0) {
         x = ~x + 1;
         sign = -1;
      }
      else {
         sign = 1;
      }
      pInt[0] = t32 x;
      pInt[1] = t32 (x >> 32);
      if (x == 0) size = 0;
      else if (pInt[1] == 0) {
         size = 1;
      }
      else {
         size = 2;
      }
      return *this;
   }

   inline friend bigInt operator+(const bigInt& lhs, const bigInt& rhs) {
      bigInt res;
      if (lhs.sign == rhs.sign) {
         int32_t maxsize = (lhs.size > rhs.size ? lhs.size : rhs.size);
         for (int i = 0; i < maxsize; i++) {
            uint64_t x = t64 lhs.pInt[i] + t64 rhs.pInt[i];
            res.pInt[i] += t32 x;
            res.pInt[i + 1] += t32 (x >> 32);
         }
         if (res.pInt[maxsize] != 0) res.size = maxsize + 1;
         else res.size = maxsize;
         res.sign = lhs.sign;
      }
      else {
         char comp = abscomp(lhs, rhs);
         if (comp == 0) return res;
         const bigInt *pbs, *pls;
         if (comp == 1) {
            res.sign = rhs.sign;
            pbs = &rhs;
            pls = &lhs;
         }
         else {
            res.sign = lhs.sign;
            pbs = &lhs;
            pls = &rhs;
         }
         int32_t maxsize = pbs->size;
         for (int i = 0; i < maxsize; i++) {
            uint64_t x = t64 pbs->pInt[i] - t64 pls->pInt[i];
            res.pInt[i] += t32 x;
            res.pInt[i + 1] += t32 (x >> 32);
         }
         for (int i = maxsize - 1; i >= 0; --i) {
            if (res.pInt[i] != 0) {
               res.size = i + 1;
               break;
            }
         }
      }
      return res;
   }

   inline friend bigInt operator-(const bigInt& lhs, bigInt rhs) {
      if (rhs.size == 0) return lhs;
      rhs.sign *= -1;
      return lhs + rhs;
   }

   inline friend bigInt operator*(const bigInt& lhs, const bigInt& rhs) {
      bigInt res;
      if (lhs.size == 0 || rhs.size == 0) return res;
      int32_t maxsize = lhs.size + rhs.size;
      for (int i = 0; i < lhs.size; i++) {
         bigInt tmp;
         for (int j = 0; j < rhs.size; j++) {
            uint64_t x = t64 lhs.pInt[i] * t64 rhs.pInt[j];
            tmp.pInt[i + j] = t32 x;
            tmp.pInt[i + j + 1] = t32 (x >> 32);
         }
         for (int k = maxsize - 1; k >= 0; --k) {
            if (tmp.pInt[k] != 0) {
               tmp.size = k + 1;
               break;
            }
         }
         res = res + tmp;
      }
      for (int k = maxsize - 1; k >= 0; --k) {
         if (res.pInt[k] != 0) {
            res.size = k + 1;
            break;
         }
      }
      res.sign = lhs.sign * rhs.sign;
      return res;
   }

   inline friend bigInt abs(bigInt x) {
      x.sign = 1;
      return x;
   }

   inline bool operator<(const bigInt& other) {
      if (sign < other.sign) return true;
      if (sign > other.sign) return false;
      if (size < other.size) return true;
      if (size > other.size) return false;
      for (int i = size - 1; i >= 0; --i) {
         if (pInt[i] < other.pInt[i]) return true;
         if (pInt[i] > other.pInt[i]) return false;
      }
      return false;
   }

   inline bool operator<=(const bigInt& other) {
      return !(*this > other);
   }

   inline bool operator>(const bigInt& other) {
      if (sign < other.sign) return false;
      if (sign > other.sign) return true;
      if (size < other.size) return false;
      if (size > other.size) return true;
      for (int i = size - 1; i >= 0; --i) {
         if (pInt[i] < other.pInt[i]) return false;
         if (pInt[i] > other.pInt[i]) return true;
      }
      return false;
   }

   inline bool operator>=(const bigInt& other) {
      return !(*this < other);
   }

   inline bool operator==(const bigInt& other) {
      if (sign != other.sign) return false;
      if (size != other.size) return false;
      for (int i = 0; i < size; i++) {
         if (pInt[i] != other.pInt[i]) return false;
      }
      return true;
   }

   inline bool operator!=(const bigInt& other) {
      return !(*this == other);
   }
};

#undef t32
#undef t64

#define inttouse bigInt<32>

inttouse xs[100000], ys[100000];

int main() {
   int n;
   scanf("%d", &n);
   int min1 = 0, min2 = 1;
   for (int i = 0; i < n; i++) {
      long long x, y;
      scanf("%lld%lld", &x, &y);
      ys[i] = y;
      xs[i] = x;
   }
   inttouse mindist = ~(1LL << 63);
   for (int i = 1; i < n; i++) {
      inttouse dist = ((xs[i] - xs[0]) * (xs[i] - xs[0])) + ((ys[i] - ys[0]) * (ys[i] - ys[0]));
      if (dist < mindist) {
         mindist = dist;
         min2 = i;
      }
   }
   int mini = 0;
   inttouse a = ys[min2] - ys[min1];
   inttouse b = xs[min1] - xs[min2];
   inttouse c = inttouse(0) - (a * xs[min1]) - (b * ys[min1]);
   mindist = ~(1LL << 63);
   for (int i = 1; i < n; i++) {
      inttouse dist = abs(a * xs[i] + b * ys[i] + c);
      if (!(dist == inttouse(0)) && dist < mindist) {
         mindist = dist;
         mini = i;
      }
   }

   printf("%d %d %d\n", min1 + 1, min2 + 1, mini + 1);

   return 0;
}


#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <list>
#include <vector>
#include <utility>
#include <queue>
#include <cmath>
#include <set>
#include <algorithm>
#include <unordered_map>

using namespace std;

#define pLL(x) *(unsigned long long*)(pInt + x)
#define respLL(x) *(unsigned long long*)(res.pInt + x)
#define tmppLL(x) *(unsigned long long*)(tmp.pInt + x)
#define tLL (unsigned long long)
#define MAX_SIZE 8
#define LAST_I MAX_SIZE - 1

class bigInt {
   union {
      unsigned int pInt[MAX_SIZE];
      unsigned long long pLL[MAX_SIZE / 2];
      unsigned char pByte[MAX_SIZE * 4];
   };
   int size;
   char sign;

public:

   bigInt() {
      size = 0;
      memset(pInt, 0, MAX_SIZE * sizeof(unsigned int));
   }

   bigInt(long long x) {
      *this = x;
   }

   inline bigInt& operator=(long long x) {
      memset(pInt, 0, MAX_SIZE * sizeof(unsigned int));
      if (x < 0) {
         sign = -1;
         x = ~x + 1;
      }
      else {
         sign = 1;
      }
      pLL(LAST_I - 1) = x;
      size = 0;
      for (int i = 63; i >= 0; --i) {
         if (x & (1LL < i)) {
            size = i + 1;
            break;
         }
      }
      return *this;
   }

   friend const bigInt operator+(const bigInt lhs, const bigInt rhs);
   friend const bigInt operator-(const bigInt lhs, const bigInt rhs);
   friend const bigInt operator*(const bigInt lhs, const bigInt rhs);

   void makeAbs() {
      sign = 1;
   }

   inline bool operator<(const bigInt& other) {
      if (size == 0 && other.size == 0) return false;
      if (sign < other.sign) return true;
      if (sign > other.sign) return false;
      if (size < other.size) return true;
      if (size > other.size) return false;
      int isize = ((size + 31) >> 5);
      for (int i = 1; i <= isize; i++) {
         if (pInt[LAST_I - isize + i] > other.pInt[LAST_I - isize + i]) return false;
         if (pInt[LAST_I - isize + i] < other.pInt[LAST_I - isize + i]) return true;
      }
      return false;
   }

   inline bool operator>(const bigInt& other) {
      if (size == 0 && other.size == 0) return false;
      if (sign < other.sign) return false;
      if (sign > other.sign) return true;
      if (size < other.size) return false;
      if (size > other.size) return true;
      int isize = ((size + 31) >> 5);
      for (int i = 1; i <= isize; i++) {
         if (pInt[LAST_I - isize + i] < other.pInt[LAST_I - isize + i]) return false;
         if (pInt[LAST_I - isize + i] > other.pInt[LAST_I - isize + i]) return true;
      }
      return false;
   }

   inline bool operator==(const bigInt& other) {
      if (size == other.size) {
         if (size == 0) return true;
         if (sign == other.sign) {
            int isize = ((size + 31) >> 5);
            for (int i = 0; i < isize; i++) {
               if (pInt[LAST_I - i] != other.pInt[LAST_I - i]) return false;
            }
            return true;
         }
      }
      return false;
   }
};

inline const bigInt operator*(const bigInt lhs, const bigInt rhs) {
   bigInt res = 0;
   unsigned int maxsize = lhs.size + rhs.size;
   res.sign = lhs.sign * rhs.sign;
   if (maxsize == 0) return res;
   int lisize = ((lhs.size + 31) >> 5);
   int risize = ((rhs.size + 31) >> 5);
   for (int i = 0; i < lisize; i++) {
      bigInt tmp = 0;
      for (int j = 0; j < risize; j++) {
         tmppLL(LAST_I - 1 - i - j) += tLL lhs.pInt[LAST_I - i] * tLL rhs.pInt[LAST_I - j];
      }
      res = res + tmp;
   }
   --maxsize;
   if (res.pInt[LAST_I - (maxsize >> 5)] & (1U << (maxsize & 31))) res.size = maxsize + 1;
   else res.size = maxsize;
   return res;
}

inline const bigInt operator+(const bigInt lhs, const bigInt rhs) {
   bigInt res = 0;
   int lsize = lhs.size, rsize = rhs.size;
   int maxsize = lsize < rsize ? rsize : lsize;
   if (maxsize == 0) return res;
   if (lhs.sign == rhs.sign) {
      res.sign = lhs.sign;
      int i = LAST_I;
      while (lsize > 0 || rsize > 0) {
         respLL(i - 1) += tLL lhs.pInt[i] + tLL rhs.pInt[i];
         lsize -= 32;
         rsize -= 32;
         --i;
      }
      if (res.pInt[LAST_I - (maxsize >> 5)] & (1U << (maxsize & 31))) res.size = maxsize + 1;
      else res.size = maxsize;
   }
   else {
      const bigInt *pbs, *pls;
      bigInt ltmp = lhs, rtmp = rhs;
      ltmp.makeAbs();
      rtmp.makeAbs();
      if (ltmp < rtmp) {
         pls = &lhs;
         pbs = &rhs;
         res.sign = rhs.sign;
      }
      else {
         pls = &rhs;
         pbs = &lhs;
         res.sign = lhs.sign;
      }
      int i = LAST_I;
      while (lsize > 0 || rsize > 0) {
         respLL(i - 1) += tLL pbs->pInt[i] - tLL pls->pInt[i];
         lsize -= 32;
         rsize -= 32;
         --i;
      }
      res.size = 0;
      for (int j = maxsize - 1; j >= 0; --j) {
         if (res.pInt[LAST_I - (j >> 5)] & (1U << (j & 31))) {
            res.size = j + 1;
            break;
         }
      }
   }

   return res;
}

inline const bigInt operator-(const bigInt lhs, const bigInt rhs) {
   bigInt newrhs = rhs;
   newrhs.sign *= -1;
   return lhs + newrhs;
}

int main() {
   int n;
   cin >> n;
   bigInt xs[100000], ys[100000];
   int min1 = 0, min2 = 1;
   for (int i = 0; i < n; i++) {
      long long x, y;
      cin >> x >> y;
      xs[i] = x;
      ys[i] = y;
   }
   bigInt mindist = ~(1LL << 63);
   for (int i = 1; i < n; i++) {
      bigInt dist = ((xs[i] - xs[0]) * (xs[i] - xs[0])) + ((ys[i] - ys[0]) * (ys[i] - ys[0]));
      if (dist < mindist) {
         mindist = dist;
         min2 = i;
      }
   }
   int mini = 0;
   bigInt a = ys[min2] - ys[min1];
   bigInt b = xs[min1] - xs[min2];
   bigInt c = bigInt(0) - (a * xs[min1]) - (b * ys[min1]);
   mindist = ~(1LL << 63);
   for (int i = 1; i < n; i++) {
      bigInt dist = a * xs[i] + b * ys[i] + c;
      dist.makeAbs();
      if (!(dist == bigInt(0)) && dist < mindist) {
         mindist = dist;
         mini = i;
      }
   }

   cout << min1 + 1 << ' ' << min2 + 1 << ' ' << mini + 1 << endl;

   return 0;
}


#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <list>
#include <vector>
#include <utility>
#include <queue>
#include <cmath>
#include <set>
#include <algorithm>
#include <unordered_map>

using namespace std;

int main() {
   int n;
   cin >> n;
   int xs[100000], ys[100000];
   int min1 = 0, min2;
   for (int i = 0; i < n; i++) {
      cin >> xs[i] >> ys[i];
   }
   unsigned long long mindist = 18446744073709551615LL;
   for (int i = 1; i < n; i++) {
      unsigned long long dist = ((xs[i] - xs[0]) * (xs[i] - xs[0])) + ((ys[i] - ys[0]) * (ys[i] - ys[0]));
      if (dist < mindist) {
         mindist = dist;
         min2 = i;
      }
   }
   int mini = 0;
   long long a = ys[min2] - ys[min1];
   long long b = xs[min1] - xs[min2];
   long long c = 0 - (a * xs[min1]) - (b * ys[min1]);
   mindist = 18446744073709551615LL;
   for (int i = 0; i < n; i++) {
      unsigned long long dist = abs(a * xs[i] + b * ys[i] + c);
      if (dist > 0 && dist < mindist) {
         mindist = dist;
         mini = i;
      }
   }

   cout << min1 + 1 << min2 + 1 << mini + 1 << endl;

   return 0;
}


#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <list>
#include <vector>
#include <utility>
#include <queue>
#include <cmath>
#include <set>
#include <algorithm>
#include <unordered_map>

using namespace std;

#define MAX_SIZE 32
#define MAX_I MAX_SIZE - 1
#define pLL *(unsigned long long *)
#define tLL (unsigned long long)

class bigInt {
   union {
      unsigned int pInt[MAX_SIZE];
      unsigned long long p_LL[MAX_SIZE / 2];
   };
   int size;
   char sign;

public:

   bigInt() {
      memset(pInt, 0, MAX_SIZE * sizeof(unsigned int));
      size = 0;
      sign = 1;
   }

   bigInt(long long x) {
      *this = x;
   }

   bigInt(const bigInt& x) {
      *this = x;
   }

   inline bigInt& operator=(const bigInt& x) {
      memcpy(this, &x, sizeof(bigInt));
      return *this;
   }

   inline bigInt& operator=(long long x) {
      memset(pInt, 0, MAX_SIZE * sizeof(unsigned int));
      if (x < 0) {
         x = ~x + 1;
         sign = -1;
      }
      else {
         sign = 1;
      }
      pLL pInt = x;
      if (x == 0) size = 0;
      else if (pInt[1] == 0) {
         size = 1;
      }
      else {
         size = 2;
      }
      return *this;
   }

   friend bigInt operator+(bigInt lhs, bigInt rhs);
   friend bigInt operator-(bigInt lhs, bigInt rhs);
   friend bigInt operator*(bigInt lhs, bigInt rhs);
   friend bigInt abs(bigInt x);

   inline bool operator<(const bigInt& other) {
      if (sign < other.sign) return true;
      if (sign > other.sign) return false;
      if (size < other.size) return true;
      if (size > other.size) return false;
      for (int i = size - 1; i >= 0; --i) {
         if (pInt[i] < other.pInt[i]) return true;
         if (pInt[i] > other.pInt[i]) return false;
      }
      return false;
   }

   inline bool operator>(const bigInt& other) {
      if (sign < other.sign) return false;
      if (sign > other.sign) return true;
      if (size < other.size) return false;
      if (size > other.size) return true;
      for (int i = size - 1; i >= 0; --i) {
         if (pInt[i] < other.pInt[i]) return false;
         if (pInt[i] > other.pInt[i]) return true;
      }
      return false;

   }

   inline bool operator==(const bigInt& other) {
      if (sign != other.sign) return false;
      if (size != other.size) return false;
      for (int i = 0; i < size; i++) {
         if (pInt[i] != other.pInt[i]) return false;
      }
      return true;
   }
};

bigInt abs(bigInt x) {
   x.sign = 1;
   return x;
}

inline bigInt operator+(bigInt lhs, bigInt rhs) {
   bigInt res;
   if (lhs.sign == rhs.sign) {
      int maxsize = (lhs.size > rhs.size ? lhs.size : rhs.size);
      for (int i = 0; i < maxsize; i++) {
         pLL(res.pInt + i) += tLL lhs.pInt[i] + tLL rhs.pInt[i];
      }
      if (res.pInt[maxsize] != 0) res.size = maxsize + 1;
      else res.size = maxsize;
      res.sign = lhs.sign;
   }
   else {
      char lsign = lhs.sign, rsign = rhs.sign;
      lhs.sign = rhs.sign = 1;
      if (lhs == rhs) return res;
      bigInt *pbs, *pls;
      if (lhs < rhs) {
         res.sign = rsign;
         pbs = &rhs;
         pls = &lhs;
      }
      else {
         res.sign = lsign;
         pbs = &lhs;
         pls = &rhs;
      }
      int maxsize = pbs->size;
      for (int i = 0; i < maxsize; i++) {
         pLL(res.pInt + i) += tLL pbs->pInt[i] - tLL pls->pInt[i];
      }
      for (int i = maxsize - 1; i >= 0; --i) {
         if (res.pInt[i] != 0) {
            res.size = i + 1;
            break;
         }
      }
   }
   return res;
}

inline bigInt operator-(bigInt lhs, bigInt rhs) {
   if (rhs.size == 0) return lhs;
   rhs.sign *= -1;
   return lhs + rhs;
}

inline bigInt operator*(bigInt lhs, bigInt rhs) {
   bigInt res;
   if (lhs.size == 0 || rhs.size == 0) return res;
   int maxsize = lhs.size + rhs.size;
   for (int i = 0; i < lhs.size; i++) {
      bigInt tmp;
      for (int j = 0; j < rhs.size; j++) {
         pLL(tmp.pInt + i + j) = tLL lhs.pInt[i] * tLL rhs.pInt[j];
      }
      for (int k = maxsize - 1; k >= 0; --k) {
         if (tmp.pInt[k] != 0) {
            tmp.size = k + 1;
            break;
         }
      }
      res = res + tmp;
   }
   for (int k = maxsize - 1; k >= 0; --k) {
      if (res.pInt[k] != 0) {
         res.size = k + 1;
         break;
      }
   }
   res.sign = lhs.sign * rhs.sign;
   return res;
}

#define inttouse bigInt

inttouse xs[100000], ys[100000];

int main() {
   int n;
   scanf("%d", &n);
   int min1 = 0, min2 = 1;
   for (int i = 0; i < n; i++) {
      long long x, y;
      scanf("%I64d%I64d", &x, &y);
      ys[i] = y;
      xs[i] = x;
   }
   inttouse mindist = ~(1LL << 63);
   for (int i = 1; i < n; i++) {
      inttouse dist = ((xs[i] - xs[0]) * (xs[i] - xs[0])) + ((ys[i] - ys[0]) * (ys[i] - ys[0]));
      if (dist < mindist) {
         mindist = dist;
         min2 = i;
      }
   }
   int mini = 0;
   inttouse a = ys[min2] - ys[min1];
   inttouse b = xs[min1] - xs[min2];
   inttouse c = inttouse(0) - (a * xs[min1]) - (b * ys[min1]);
   mindist = ~(1LL << 63);
   for (int i = 1; i < n; i++) {
      inttouse dist = abs(a * xs[i] + b * ys[i] + c);
      if (!(dist == inttouse(0)) && dist < mindist) {
         mindist = dist;
         mini = i;
      }
   }

   printf("%d %d %d\n", min1 + 1, min2 + 1, mini + 1);

   return 0;
}


#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <list>
#include <vector>
#include <utility>
#include <queue>
#include <cmath>
#include <set>
#include <algorithm>
#include <unordered_map>

using namespace std;

int main() {
   int n;
   cin >> n;
   int xs[100000], ys[100000];
   int min1 = 0, min2 = 1;
   cin >> xs[0] >> ys[0];
   cin >> xs[1] >> ys[1];
   if (xs[0] > xs[1]) {
      min1 = 1; min2 = 0;
   }
   else if (xs[0] == xs[1]) {
      if (ys[0] > ys[1]) {
         min1 = 1; min2 = 0;
      }
   }
   for (int i = 2; i < n; i++) {
      cin >> xs[i] >> ys[i];
      if (xs[i] < xs[min1]) {
         min2 = min1;
         min1 = i;
      }
      else if (xs[i] == xs[min1]) {
         if (ys[i] <= ys[min1]) {
            min2 = min1;
            min1 = i;
         }
      }
      else if (xs[i] < xs[min2]) {
         min2 = i;
      }
      else if (xs[i] == xs[min2]) {
         if (ys[i] <= ys[min2]) {
            min2 = i;
         }
      }
   }
   int mini = 0;
   if (xs[min1] == xs[min2]) {
      int mindist = 1000000001;
      for (int i = 0; i < n; i++) {
         int dist = abs(xs[i] - xs[min1]);
         if (dist > 0 && dist < mindist) {
            mindist = dist;
            mini = i;
         }
      }
   }
   else if (ys[min1] == ys[min2]) {
      int mindist = 1000000001;
      for (int i = 0; i < n; i++) {
         int dist = abs(ys[i] - ys[min1]);
         if (dist > 0 && dist < mindist) {
            mindist = dist;
            mini = i;
         }
      }
   }
   else {
      long double a = (ys[min2] - ys[min1]) / (xs[min2] - xs[min1]);
      long double b = ys[min1] - (a * xs[min1]);
      long double mindist = 10e90L;
      for (int i = 0; i < n; i++) {
         if (i == min1 || i == min2) continue;
         long double dist = abs(a * xs[i] - ys[i] + b) / sqrt(a * a + 1);
         if (dist > 0.000000001 && dist < mindist) {
            mindist = dist;
            mini = i;
         }
      }
   }

   cout << min1 + 1 << min2 + 1 << mini + 1 << endl;

   return 0;
}


#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <list>
#include <vector>
#include <utility>
#include <queue>
#include <cmath>
#include <set>
#include <algorithm>
#include <unordered_map>

using namespace std;

int main() {
   int n;
   cin >> n;
   long double xs[100000], ys[100000];
   int min1 = 0, min2;
   for (int i = 0; i < n; i++) {
      cin >> xs[i] >> ys[i];
   }
   long double mindist = 10e120L;
   for (int i = 1; i < n; i++) {
      long double dist = ((xs[i] - xs[0]) * (xs[i] - xs[0])) + ((ys[i] - ys[0]) * (ys[i] - ys[0]));
      if (dist < mindist) {
         mindist = dist;
         min2 = i;
      }
   }
   int mini = 0;
   long double a = ys[min2] - ys[min1];
   long double b = xs[min1] - xs[min2];
   long double c = 0 - (a * xs[min1]) - (b * ys[min1]);
   mindist = 10e120L;
   for (int i = 1; i < n; i++) {
      long double dist = abs(a * xs[i] + b * ys[i] + c);
      if (dist > 0.0000001L && dist < mindist) {
         mindist = dist;
         mini = i;
      }
   }

   cout << min1 + 1 << ' ' << min2 + 1 << ' ' << mini + 1 << endl;

   return 0;
}


#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <list>
#include <vector>
#include <utility>
#include <queue>
#include <cmath>
#include <set>
#include <algorithm>
#include <unordered_map>

using namespace std;

int main() {
   int n;
   cin >> n;
   int xs[100000], ys[100000];
   int min1 = 0, min2;
   for (int i = 0; i < n; i++) {
      cin >> xs[i] >> ys[i];
   }
   long double mindist = 10e120L;
   for (int i = 1; i < n; i++) {
      unsigned long double dist = ((xs[i] - xs[0]) * (xs[i] - xs[0])) + ((ys[i] - ys[0]) * (ys[i] - ys[0]));
      if (dist < mindist) {
         mindist = dist;
         min2 = i;
      }
   }
   int mini = 0;
   long long a = ys[min2] - ys[min1];
   long long b = xs[min1] - xs[min2];
   long long c = 0 - (a * xs[min1]) - (b * ys[min1]);
   mindist = 10e120L;
   for (int i = 1; i < n; i++) {
      unsigned long double dist = abs(a * xs[i] + b * ys[i] + c);
      if (dist > 0.0000001L && dist < mindist) {
         mindist = dist;
         mini = i;
      }
   }

   cout << min1 + 1 << ' ' << min2 + 1 << ' ' << mini + 1 << endl;

   return 0;
}


#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <list>
#include <vector>
#include <utility>
#include <queue>
#include <cmath>
#include <set>
#include <algorithm>
#include <unordered_map>

using namespace std;

int main() {
   int n;
   cin >> n;
   int xs[100000], ys[100000];
   int min1 = 0, min2 = 1;
   cin >> xs[0] >> ys[0];
   cin >> xs[1] >> ys[1];
   if (xs[0] > xs[1]) {
      min1 = 1; min2 = 0;
   }
   else if (xs[0] == xs[1]) {
      if (ys[0] > ys[1]) {
         min1 = 1; min2 = 0;
      }
   }
   for (int i = 2; i < n; i++) {
      cin >> xs[i] >> ys[i];
      if (xs[i] < xs[min1]) {
         min2 = min1;
         min1 = i;
      }
      else if (xs[i] == xs[min1]) {
         if (ys[i] <= ys[min1]) {
            min2 = min1;
            min1 = i;
         }
      }
      else if (xs[i] < xs[min2]) {
         min2 = i;
      }
      else if (xs[i] == xs[min2]) {
         if (ys[i] <= ys[min2]) {
            min2 = i;
         }
      }
   }
   int mini = 0;
   long long a = ys[min2] - ys[min1];
   long long b = xs[min1] - xs[min2];
   long long c = 0 - (a * xs[min1]) - (b * ys[min1]);
   long long mindist = 2LL * 2000000000LL * 2000000000LL + 1LL;
   for (int i = 0; i < n; i++) {
      if (i == min1 || i == min2) continue;
      long long dist = abs(a * xs[i] + b * ys[i] + c);
      if (dist > 0 && dist < mindist) {
         mindist = dist;
         mini = i;
      }
   }

   cout << min1 + 1 << min2 + 1 << mini + 1 << endl;

   return 0;
}


#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <list>
#include <vector>
#include <utility>
#include <queue>
#include <cmath>
#include <set>
#include <algorithm>
#include <unordered_map>

using namespace std;

#define pLL(x) *(unsigned long long*)(pInt + x)
#define respLL(x) *(unsigned long long*)(res.pInt + x)
#define tmppLL(x) *(unsigned long long*)(tmp.pInt + x)
#define tLL (unsigned long long)
#define MAX_SIZE 8
#define LAST_I MAX_SIZE - 1

class bigInt {
   unsigned int pInt[MAX_SIZE];
   int size;
   char sign;

public:

   bigInt() {
      size = 0;
      memset(pInt, 0, MAX_SIZE * sizeof(unsigned int));
   }

   bigInt(long long x) {
      *this = x;
   }

   inline bigInt& operator=(long long x) {
      memset(pInt, 0, MAX_SIZE * sizeof(unsigned int));
      if (x < 0) {
         sign = -1;
         x = ~x + 1;
      }
      else {
         sign = 1;
      }
      pLL(LAST_I - 1) = x;
      size = 0;
      for (int i = 63; i >= 0; --i) {
         if (x & (1LL < i)) {
            size = i + 1;
            break;
         }
      }
      return *this;
   }

   inline bigInt operator+(bigInt& rhs) {
      bigInt& lhs = *this;
      bigInt res = 0;
      int lsize = lhs.size, rsize = rhs.size;
      int maxsize = lsize < rsize ? rsize : lsize;
      if (maxsize == 0) return res;
      if (sign == rhs.sign) {
         res.sign = lhs.sign;
         int i = LAST_I;
         while (lsize > 0 || rsize > 0) {
            respLL(i - 1) += tLL lhs.pInt[i] + tLL rhs.pInt[i];
            lsize -= 32;
            rsize -= 32;
            --i;
         }
         if (res.pInt[LAST_I - (maxsize >> 5)] & (1U << (maxsize & 31))) res.size = maxsize + 1;
         else res.size = maxsize;
      }
      else {
         char lsign = lhs.sign, rsign = rhs.sign;
         bigInt *pbs, *pls;
         lhs.sign = rhs.sign = 1;
         if (lhs < rhs) {
            pls = &lhs;
            pbs = &rhs;
            res.sign = rsign;
         }
         else {
            pls = &rhs;
            pbs = &lhs;
            res.sign = lsign;
         }
         int i = LAST_I;
         while (lsize > 0 || rsize > 0) {
            respLL(i - 1) += tLL pbs->pInt[i] - tLL pls->pInt[i];
            lsize -= 32;
            rsize -= 32;
            --i;
         }
         res.size = 0;
         for (int j = maxsize - 1; j >= 0; --j) {
            if (res.pInt[LAST_I - (j >> 5)] & (1U << (j & 31))) {
               res.size = j + 1;
               break;
            }
         }
      }

      return res;
   }

   inline bigInt operator-(bigInt& rhs) {
      bigInt& lhs = *this;
      bigInt newrhs = rhs;
      newrhs.sign *= -1;
      return lhs + newrhs;
   }

   inline bigInt operator*(bigInt& rhs) {
      bigInt& lhs = *this;
      bigInt res = 0;
      unsigned int maxsize = lhs.size + rhs.size;
      res.sign = lhs.sign * rhs.sign;
      if (maxsize == 0) return res;
      int lisize = ((lhs.size + 31) >> 5);
      int risize = ((rhs.size + 31) >> 5);
      for (int i = 0; i < lisize; i++) {
         bigInt tmp = 0;
         for (int j = 0; j < risize; j++) {
            tmppLL(LAST_I - 1 - i - j) += tLL lhs.pInt[LAST_I - i] * tLL rhs.pInt[LAST_I - j];
         }
         res = res + tmp;
      }
      --maxsize;
      if (res.pInt[LAST_I - (maxsize >> 5)] & (1U << (maxsize & 31))) res.size = maxsize + 1;
      else res.size = maxsize;
      return res;
   }

   inline bigInt operator/(bigInt& rhs) {

   }

   inline bigInt operator%(bigInt& rhs) {

   }

   void makeAbs() {
      sign = 1;
   }

   inline bool operator<(bigInt& other) {
      if (*this == other) return false;
      if (sign > other.sign) return true;
      if (sign < other.sign) return false;
      if (size < other.size) return true;
      if (size > other.size) return false;
      int isize = ((size + 31) >> 5);
      for (int i = 1; i <= isize; i++) {
         if (pInt[LAST_I - isize + i] > other.pInt[LAST_I - isize + i]) return false;
      }
      return true;
   }

   inline bool operator>(bigInt& other) {
      if (*this == other) return false;
      if (sign > other.sign) return false;
      if (sign < other.sign) return true;
      if (size < other.size) return false;
      if (size > other.size) return true;
      int isize = ((size + 31) >> 5);
      for (int i = 1; i <= isize; i++) {
         if (pInt[LAST_I - isize + i] < other.pInt[LAST_I - isize + i]) return false;
      }
      return true;
   }

   inline bool operator==(bigInt& other) {
      if (size == other.size) {
         if (size == 0) return true;
         if (sign == other.sign) {
            int isize = ((size + 31) >> 5);
            for (int i = 0; i < isize; i++) {
               if (pInt[LAST_I - i] != other.pInt[LAST_I - i]) return false;
            }
            return true;
         }
      }
      return false;
   }
};

int main() {
   int n;
   cin >> n;
   bigInt xs[100000], ys[100000];
   int min1 = 0, min2;
   for (int i = 0; i < n; i++) {
      long long x, y;
      cin >> x >> y;
      xs[i] = x;
      ys[i] = y;
   }
   bigInt mindist = ~(1LL << 63);
   for (int i = 1; i < n; i++) {
      bigInt dist = ((xs[i] - xs[0]) * (xs[i] - xs[0])) + ((ys[i] - ys[0]) * (ys[i] - ys[0]));
      if (dist < mindist) {
         mindist = dist;
         min2 = i;
      }
   }
   int mini = 0;
   bigInt a = ys[min2] - ys[min1];
   bigInt b = xs[min1] - xs[min2];
   bigInt c = bigInt(0) - (a * xs[min1]) - (b * ys[min1]);
   mindist = ~(1LL << 63);
   for (int i = 1; i < n; i++) {
      bigInt dist = a * xs[i] + b * ys[i] + c;
      dist.makeAbs();
      if (!(dist == bigInt(0)) && dist < mindist) {
         mindist = dist;
         mini = i;
      }
   }

   cout << min1 + 1 << ' ' << min2 + 1 << ' ' << mini + 1 << endl;

   return 0;
}


#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <list>
#include <vector>
#include <utility>
#include <queue>
#include <cmath>
#include <set>
#include <algorithm>
#include <unordered_map>

using namespace std;

int main() {
   int n;
   cin >> n;
   int xs[100000], ys[100000];
   int min1 = 0, min2;
   for (int i = 0; i < n; i++) {
      cin >> xs[i] >> ys[i];
   }
   unsigned long long mindist = 2LL * 2000000000LL * 2000000000LL + 1LL;
   for (int i = 1; i < n; i++) {
      unsigned long long dist = ((xs[i] - xs[0]) * (xs[i] - xs[0])) + ((ys[i] - ys[0]) * (ys[i] - ys[0]));
      if (dist < mindist) {
         mindist = dist;
         min2 = i;
      }
   }
   int mini = 0;
   long long a = ys[min2] - ys[min1];
   long long b = xs[min1] - xs[min2];
   long long c = 0 - (a * xs[min1]) - (b * ys[min1]);
   mindist = 2LL * 2000000000LL * 2000000000LL + 1LL;
   for (int i = 0; i < n; i++) {
      if (i == min1 || i == min2) continue;
      unsigned long long dist = abs(a * xs[i] + b * ys[i] + c);
      if (dist > 0 && dist < mindist) {
         mindist = dist;
         mini = i;
      }
   }

   cout << min1 + 1 << min2 + 1 << mini + 1 << endl;

   return 0;
}