题目
思路
一眼二分,把平面分成两部分,查左右两边,但是还有可能跨中间的线,所以这个也得判
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=4e5+10;
pair<int,int> a[maxn];
int n;
int d=1e16;
pair<int,int> vl[maxn],vr[maxn];
void read() { cin>>n;for(int i=1;i<=n;i++) cin>>a[i].first>>a[i].second; }
int dis2(pair<int,int> a,pair<int,int> b) { return (a.first-b.first)*(a.first-b.first)+(a.second-b.second)*(a.second-b.second); }
void solve(int l,int r){
if(l==r) { swap(a[l].first,a[l].second);return; }//一开始sort是按照x排的,为了算跨中间线的情况再按照y排
int mid=l+r>>1;int x=a[mid].first;
solve(l,mid),solve(mid+1,r);
double dis=sqrt(d);
int sl=0,sr=0;
//找到两边的点集
for(int i=l;i<=mid;i++) if(x-a[i].second<dis) vl[++sl]=a[i];
for(int i=mid+1;i<=r;i++) if(a[i].second-x<dis) vr[++sr]=a[i];
int p=1,q=0;
for(int i=1;i<=sl;i++){
//找到y的范围
while(p<=sr&&vl[i].first-vr[p].first>=dis) p++;
while(q<sr&&vr[q+1].first-vl[i].first<dis) q++;
for(int j=p;j<=q;j++) d=min(d,dis2(vl[i],vr[j]));//跨中间线判断
}
inplace_merge(a+l,a+mid+1,a+r+1);//归并
}
signed main()
{
read();
sort(a+1,a+1+n);
solve(1,n);
cout<<d;
return 0;
}
end
完结撒花