Problem:
Convex Hull

Find the convex hull of a given set of points P. In other words, find the smallest convex polygon containing all the points of P. Here, in a convex polygon, all interior angles are less than or equal to 180 degrees.

Please note that you should find all the points of P on both corner and boundary of the convex polygon.

Input

n
x1 y1
x2 y2
:
xn yn

The first integer n is the number of points in P. The coordinate of the i-th point pi is given by two integers xi and yi.

Output

In the first line, print the number of points on the corner/boundary of the convex polygon. In the following lines, print x y coordinates of the set of points.
The coordinates should be given in the order of counter-clockwise visit of them starting from the point in P with the minimum y-coordinate, or the leftmost such point in case of a tie.

Constraints

3 ≤ n ≤ 100000

-10000 ≤ xi, yi ≤ 10000

No point in the P will occur more than once.

Sample Input 1

7
2 1
0 0
1 2
2 2
4 2
1 3
3 3

Sample Output 1

5
0 0
2 1
4 2
3 3
1 3

Sample Input 2

4
0 0
2 2
0 2
0 1

Sample Output 2

4
0 0
2 2
0 2
0 1

Solution in C++ (judge verdict: Time Limit Exceeded)

#define _USE_MATH_DEFINES
#include <climits>
#include<cmath>
#include<iostream>
#include<math.h>
#include<stdlib.h>
#include<utility>
#include<vector>

class Points{
private:
    
	std::pair<int,int> nCood;
	double dArg;
    double dLength_2;
public:
	Points(){
		nCood.first = nCood.second = dArg = dLength_2 = 0;
	}
	void SetPoint (int nInX, int nInY){
	nCood.first=nInX;
	nCood.second=nInY;
	return;
	}
    std::pair<int,int>nnGetCood(){
	return nCood;
	}
	void SetArg (Points StartPoint ){
		
		double dLengthVector=std::sqrt((nCood.first-(StartPoint.nnGetCood()).first)*(nCood.first-(StartPoint.nnGetCood()).first)+(nCood.second-(StartPoint.nnGetCood()).second)*(nCood.second-(StartPoint.nnGetCood()).second)*1.);
		double dCos=(nCood.first-(StartPoint.nnGetCood()).first)/dLengthVector;
		dArg=std::acos(dCos);
		return;
	}
    void SetLength (Points StartPoint){
        dLength_2 = (nCood.first - StartPoint.nnGetCood().first)*(nCood.first - StartPoint.nnGetCood().first) 
                    + (nCood.second - StartPoint.nnGetCood().second)*(nCood.second - StartPoint.nnGetCood().second);
        return;
    }
	
	double dGetArg(){
	return dArg;
	}
    double dGetLength_2(){
	return dLength_2;
	}
};

/*
*?????????????????????
*/
void quick_sort_part(std::vector<Points>&points,int left,int right);
int partition(std::vector<Points>&points,int left,int right);
/*
*????????§????????????????¶?
*/
void quick_sort_part_2(std::vector<Points>&points,int nUpDown ,int left,int right);
int partition_2(std::vector<Points>&points,int nUpDown,int left,int right);
/*
*??????dArg??????????????????????????????????????????????????????
*?????????points[0]??????????????¢??§?±??????????
*/
void judgeIsometric(std::vector<Points>&points);
/*
*??????????¬?????????£(true)??????????????§???i???????????¶?????????????????????????????????
*1<=i<=points.size()-2,i==points.size()-2
*/
bool bCrossProduct (std::vector<Points >&points,int i){
       
    if(i>points.size()-1){return true;}
    double dValueCrossPro;
    if(1<=i&&i<=points.size()-2){
     dValueCrossPro = (points[i].nnGetCood().first - points[i-1].nnGetCood().first) * (points[i+1].nnGetCood().second - points[i].nnGetCood().second)
                        -(points[i].nnGetCood().second - points[i-1].nnGetCood().second) * (points[i+1].nnGetCood().first - points[i].nnGetCood().first) ;
    return dValueCrossPro >= 0;
    }
    else if(i==points.size()-1){
     dValueCrossPro = (points[i].nnGetCood().first - points[i-1].nnGetCood().first) * (points[0].nnGetCood().second - points[i].nnGetCood().second)
                        -(points[i].nnGetCood().second - points[i-1].nnGetCood().second) * (points[0].nnGetCood().first - points[i].nnGetCood().first) ;
    return dValueCrossPro >= 0;
    }
    else {
        std::cout<<"errorCrossProduct"<<std::endl;
        return false;}
}
bool bIsPararell(std::vector<Points>&points,int nI,int nJ);
int main(void){
	/*
	*??¶???????????¨???
	*/
	std::ios::sync_with_stdio(false);
	int nInput;
	std::cin >> nInput;
	std::vector<Points> aComp_nPoints(nInput);
	int nInputX,nInputY,nMinX = INT_MAX,nMinY = INT_MAX;
	int nIndexMin;
	for (int i = 0;i < nInput;++i){
		std::cin >> nInputX >> nInputY;
		
			aComp_nPoints[i].SetPoint(nInputX,nInputY);
            if (nMinY == nInputY && nMinX > nInputX){
                nMinX = nInputX;
                nIndexMin = i;
            }
            else if (nMinY > nInputY){
				nMinY = nInputY;
                nMinX = nInputX;
                nIndexMin = i;
            
			}
            
	}
	/*
	*??¶??????????????§y???????°??????§????????????????????§?????????x????°???????????????¢???
	*/
	if (nIndexMin != 0){
	std::swap(aComp_nPoints[0],aComp_nPoints[nIndexMin]);
	}
	/*
	*aComp_nPoints[0]????????????????§?????±????????°?????????????aComp_nPoints[i>0]?????????????????????
	*/
	for(int i = 1;i < nInput;++i){
		aComp_nPoints[i].SetArg ( aComp_nPoints[0] );
	}
    quick_sort_part(aComp_nPoints,0,aComp_nPoints.size()-1);
	
    
    judgeIsometric (aComp_nPoints);


  
    int nIndex=1;
    for (int i = 1; i <aComp_nPoints.size()-1 ; ++i){
  
         while (!bCrossProduct (aComp_nPoints, i)){
             aComp_nPoints.erase(aComp_nPoints.begin()+i);
            --i;
        }
       
    }
    std::cout << aComp_nPoints.size() << "\n";
    
    for (int i = 0 ;i < aComp_nPoints.size(); ++i){
       std::cout << aComp_nPoints[i].nnGetCood().first << " " << aComp_nPoints[i].nnGetCood().second << "\n";
    }
   //system ("pause");
	return 0;
}

int partition (std::vector<Points>&points,int left,int right){
    
    double dValue = points[right].dGetArg();
    int iIndex = left-1;
    for (int j = left;j <= right-1;++j){
        if(points[j].dGetArg() <= dValue){
        ++iIndex;
        std::swap(points[iIndex],points[j]);
        }
    }
    std::swap(points[iIndex+1],points[right]);
        return iIndex+1;
}
void quick_sort_part (std::vector<Points>&points,int left,int right){
    if (left<right){
        int nMiddleIndex=partition(points, left, right);
        quick_sort_part ( points, left, nMiddleIndex-1);
        quick_sort_part ( points, nMiddleIndex+1, right);
    }

    return;   
}

int partition_2 (std::vector<Points>&points,int nUpDown,int left,int right){
    
    double dValue = points[right].dGetLength_2();
    int iIndex = left-1;
    for (int j = left;j <= right-1;++j){
        if(nUpDown==1&&points[j].dGetLength_2() <= dValue){
        ++iIndex;
        std::swap(points[iIndex],points[j]);
        }
        else  if(nUpDown==-1&&points[j].dGetLength_2() >= dValue){
        ++iIndex;
        std::swap(points[iIndex],points[j]);
        }
    }
    std::swap(points[iIndex+1],points[right]);
        return iIndex+1;
}
void quick_sort_part_2 (std::vector<Points>&points,int nUpDown,int left,int right){
    if (left < right){
        int nMiddleIndex = partition_2(points,nUpDown, left, right);
        quick_sort_part_2 ( points,nUpDown, left, nMiddleIndex - 1);
        quick_sort_part_2 ( points,nUpDown, nMiddleIndex + 1, right);
    }

    return;   
}

void judgeIsometric (std::vector<Points>&points){
    points[points.size() - 1].SetLength(points[0]);
    int iLeft=1,iRight=1;
    for (int i = 1 ; i < points.size() - 1 ; ++i){
        if (bIsPararell (points,i,i+1)){
            iRight=i+1;
            if(!points[i].dGetLength_2()){
                points[i].SetLength(points[0]);          
            }
            points[i+1].SetLength(points[0]);
               if (iRight==points.size() - 1){
                quick_sort_part_2 (points,-1,iLeft,iRight);
                }
            }
        else{
            if (iLeft!=iRight){
                if (iLeft==1){
                quick_sort_part_2 (points,1,iLeft,iRight);
                }
              
                else{
                quick_sort_part_2 (points,-1,iLeft,iRight);
                points.erase(points.begin() + iLeft + 1,points.begin() +iRight );
                }
            }
            iLeft = iRight =i+1;
        }
    }    
    return;
}
bool bIsPararell(std::vector<Points>&points,int nI,int nJ){
  int nPararellCriterion =   (points[nI].nnGetCood().first - points[0].nnGetCood().first) * (points[nJ].nnGetCood().second - points[0].nnGetCood().second)
                           -(points[nJ].nnGetCood().first - points[0].nnGetCood().first) * (points[nI].nnGetCood().second - points[0].nnGetCood().second);
  return nPararellCriterion ==0;
}