#include<bits/stdc++.h>using namespace std;typedef const long long ll;struct node{ int x,y; int pos;}plane[200020],tubao[200020],stt;int top;int n;long long multi(node a,node b,node c){ ll mianji=1ll*(a.x-c.x)*(b.y-c.y)-1ll*(a.y-c.y)*(b.x-c.x);//面积公式判断正负值 return mianji;}bool cmp(node a,node b){ if(a.x==b.x&&a.y==b.y) return a.pos>b.pos;//重复点,字典序大的排在前(此处如果将字典序小的排在前,则WA,原因未知) if(!multi(stt,b,a))//两个点与原点的连线斜率相等,即三点共线 return pow(a.x-stt.x,2)+pow(a.y-stt.y,2)<pow(b.x-stt.x,2)+pow(b.y-stt.y,2); //和原点距离近的排在前 return multi(stt,b,a)>0;//multi为正说明联接凸包的顺序a在b之前(a在b下面如果纵坐标相等a横坐标更小)}void graham(){ tubao[1]=plane[1]; tubao[2]=plane[2]; top=3; for(int i=3;i<=n;i++) { while(top>2&&multi(tubao[top-2],plane[i],tubao[top-1])<=0) { if(multi(tubao[top-2],plane[i],tubao[top-1])<0||plane[i].pos<tubao[top-1].pos)//处理字典序问题 //该点应在栈中第二点之前联接凸包或者和第二点重合然而字典序靠前 top--; else break; } tubao[top++]=plane[i];//用栈模拟联接凸包顺序 } for(int i=1;i<top;i++) { printf("%d%c",tubao[i].pos,i==top-1?'\n':' '); }}int main(){ int t; scanf("%d",&t); while(t--) { scanf("%d",&n); int x,y; for(int i=1;i<=n;i++) { scanf("%d%d",&x,&y); plane[i].x=x; plane[i].y=y; plane[i].pos=i; } stt=plane[1]; sort(plane+2,plane+1+n,cmp);//起点不参与排序 graham(); } return 0;}
//坐标排序待补