usingPoint=pair<double,double>;#define x first#define y secondPointoperator+(Pointa,Pointb){return{a.x+b.x,a.y+b.y};}Pointoperator-(Pointa,Pointb){return{a.x-b.x,a.y-b.y};}Pointoperator*(Pointa,doubled){return{d*a.x,d*a.y};}doubledot(Pointa,Pointb){returna.x*b.x+a.y*b.y;}doublecross(Pointa,Pointb){returna.x*b.y-a.y*b.x;}
doubledisPS(Pointa,Pointb,Pointc){// Seg(a, b) Point(c)if(onseg(a,b,c))return0;if(dot(c-a,b-a)<0)returndis(c,a);if(dot(c-b,a-b)<0)returndis(b,a);return(double)abs(cross(c-a,b-a))/len(b-a);}
doubledisSS(Pointa,Pointb,Pointc,Pointd){// Seg(a, b) Seg(c, d)if(intersect(a,b,c,d))return0;returnmin({disPS(a,b,c),disPS(a,b,d),disPS(c,d,a),disPS(c,d,b)});}
#include<bits/stdc++.h>#define int long long#define x first#define y secondusingnamespacestd;usingPoint=pair<double,double>;intn,m;vector<Point>p;Pointoperator+(Pointa,Pointb){return{a.x+b.x,a.y+b.y};}Pointoperator-(Pointa,Pointb){return{a.x-b.x,a.y-b.y};}Pointoperator*(Pointa,doubled){return{a.x*d,a.y*d};}intdot(Pointa,Pointb){returna.x*b.x+a.y*b.y;}intcross(Pointa,Pointb){returna.x*b.y-a.y*b.x;}intsign(intx){if(x<0)return-1;if(x==0)return0;return1;}boolonseg(Pointa,Pointb,Pointc){if(cross(c-a,b-a)!=0)returnfalse;if(dot(c-a,b-a)<0)returnfalse;if(dot(a-b,c-b)<0)returnfalse;returntrue;}intintersect(Pointa,Pointb,Pointc,Pointd){intc1=sign(cross(b-a,c-a))*sign(cross(b-a,d-a));intc2=sign(cross(d-c,b-c))*sign(cross(d-c,a-c));if(c1==1||c2==1)returnfalse;if(c1==-1&&c2==-1)returntrue;if(onseg(a,b,c))returntrue;if(onseg(a,b,d))returntrue;if(onseg(c,d,a))returntrue;if(onseg(c,d,b))returntrue;returnfalse;}voidsolve(){Pointtar;cin>>tar.x>>tar.y;for(inti=1;i<n;i++){if(onseg(p[i-1],p[i],tar)){cout<<"BOUNDARY";return;}}if(onseg(p[0],p[n-1],tar)){cout<<"BOUNDARY";return;}Pointcmp=tar+(Point){1,2e9+1};intcnt=0;for(inti=1;i<n;i++){if(intersect(p[i-1],p[i],cmp,tar)){cnt++;}}if(intersect(p[0],p[n-1],cmp,tar)){cnt++;}if(cnt&1)cout<<"INSIDE";elsecout<<"OUTSIDE";}signedmain(){cin>>n>>m;p.resize(n);for(inti=0;i<n;i++){cin>>p[i].x>>p[i].y;}while(m--){solve();cout<<"\n";}}
這邊就以找下凸包為例,排序好後第一個點,也就是最左邊的點,一定會在凸包裡面,所以我們將他加入,之後,當新的點新增進來時,若加來發現會與前面的向量呈現「凹陷狀態」,也就是 cross < 01,則一直 pop 當前凸包尾端的點直到不會凹陷,因為這些被 pop 的點都會被新的點與之前的點所連接的向量包含住
注意直接套我們上面的凸包模板,加上面積公式即可,就算凸包模板起點會現兩次也是 ok 的,不能在最後把起點 pop 掉
把最後重複出現的起點 pop 掉也可以,但要記得將 area() 函式內的細節改一下,防止 n = 1 時,凸包把所有點都 pop 掉的 edge case
doublearea(vector<Point>&points){intn=points.size();intret=0;for(inti=1;i<n;i++){ret+=cross(points[i],points[i-1]);}// 前面加上 if (n),防止 n = 0if(n)ret+=cross(points[0],points[n-1]);returnfabs((double)ret/2);}
#include<bits/stdc++.h>#define int long long#define pii pair<int, int>#define mk make_pair#define pb push_back#define x first#define y second#define ALL(x) x.begin(), x.end()usingnamespacestd;usingPoint=pair<int,int>;Pointoperator+(Pointa,Pointb){return{a.x+b.x,a.y+b.y};}Pointoperator-(Pointa,Pointb){return{a.x-b.x,a.y-b.y};}Pointoperator*(Pointa,doubled){return{a.x*d,a.y*d};}intdot(Pointa,Pointb){returna.x*b.x+a.y*b.y;}intcross(Pointa,Pointb){returna.x*b.y-a.y*b.x;}doublearea(vector<Point>&points){intn=points.size();intret=0;for(inti=1;i<n;i++){ret+=cross(points[i],points[i-1]);}ret+=cross(points[0],points[n-1]);returnfabs((double)ret/2);}vector<Point>convex_hull(vector<Point>p){intn=p.size(),m=0;sort(p.begin(),p.end());vector<Point>h;for(inti=0;i<n;i++){while(m>=2&&cross(p[i]-h[m-1],h[m-1]-h[m-2])<0){h.pop_back(),m--;}h.push_back(p[i]),m++;}for(inti=n-2;i>=0;i--){while(m>=2&&cross(p[i]-h[m-1],h[m-1]-h[m-2])<0){h.pop_back(),m--;}h.push_back(p[i]),m++;}returnh;}intn;voidsolve(){vector<Point>p;p.resize(n);for(inti=0;i<n;i++){cin>>p[i].x>>p[i].y;}vector<Point>h=convex_hull(p);cout<<fixed<<setprecision(2)<<area(h)<<'\n';}signedmain(){while(cin>>n){if(n==0)break;solve();}}
先把整個陣列 p 按照 x 小到大 sort。以中位數當 pivot,依照 x 軸分成左、右兩堆,遞迴求解子問題,再來 Combine 的部分,我們把以中位數那條線左右距離 <= d 的點都拿出來,按照 y 小到大 sort,對於每個點都只要看周圍至多 6 個點的距離即可,因為我們可以利用類似 Merge sort 的方式得到已 y 小到大 sort 的 p',所以複雜度是 O(n log n)
combine(d, P, mid) {
P 只留 x \in [mid - d, mid + d]
每個 P 內的 point,只和上下 8 個點算 distance
用類似雙指針維護
}
DC(P) {
(d1, P_L') = DC(P.前半)
(d2, P_R') = DC(P.後半)
P' = merge(P_L', P_R') by y 小到大
d = min(d1, d2)
combine(d, P', mid)
}
#include<bits/stdc++.h>#define int long long#define x first#define y second#define pii pair<int, int>usingnamespacestd;constintINF=9e18;intdis(piia,piib){intx=a.x-b.x,y=a.y-b.y;returnx*x+y*y;}signedmain(){intn;cin>>n;vector<pair<int,int>>p(n);for(inti=0;i<n;i++){cin>>p[i].x>>p[i].y;}sort(p.begin(),p.end());set<pair<int,int>>s;s.clear();s.insert({p[0].y,p[0].x});intl=0,ans=INF;for(inti=1;i<n;i++){intd=ceil(sqrt(ans));while(l<i&&p[l].x<p[i].x-d){s.erase({p[l].y,p[l].x});l++;}autoit_l=s.lower_bound({p[i].y-d,0});autoit_r=s.upper_bound({p[i].y+d,0});for(autoit=it_l;it!=it_r;it++){ans=min(ans,dis({it->y,it->x},p[i]));}s.insert({p[i].y,p[i].x});}cout<<ans<<'\n';}