n个点每次减去一个点,求n种状态的最近距离的和
跑一遍临近点对求出总体最近距离同时记录最近距离确定的两个点的编号
最近距离确定的两个点以外消去的话对最近距离并不影响,那结果加(n-2)个最近距离就行了
然后删掉最近距离确定的两个点的其中之一再跑两遍临近点对求出两个最近距离加到结果上几近模板题。。。
#include<cstdio>
#include<vector>
#include<algorithm>
#include<iostream>
#include<cmath>
#define LL long long
#define pi acos(-1.0)
#define maxn 100005
#define ma 0x7ffffffffffll
using namespace std;
struct node{
LL x,y,index;
}no[maxn],no2[maxn],no3[maxn];
LL n,flag1,flag2;
LL ans;
LL cmpX(node a,node b)
{
return a.x<b.x;
}
LL cmpY(node a,node b)
{
return a.y<b.y;
}
LL dis(node a,node b)
{
return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
void closet(int s,int e,node *no)
{
if(e-s==1)
{
LL pre = dis(no[s],no[e]);
if(pre<ans)
{
ans = pre;
flag1 = no[s].index;
flag2 = no[e].index;
}
return ;
}
if(e-s==2)
{
LL pre1 = dis(no[s],no[s+1]),pre2 = dis(no[s+1],no[e]),pre3 = dis(no[s],no[e]);
if(ans>pre1)
{
ans = pre1;
flag1 = no[s].index;
flag2 = no[s+1].index;
}
if(ans>pre2)
{
ans = pre2;
flag1 = no[s+1].index;
flag2 = no[e].index;
}
if(ans>pre3)
{
ans = pre3;
flag1 = no[s].index;
flag2 = no[e].index;
}
return ;
}
int mid = (s+e)>>1;
closet(s,mid,no);
closet(mid+1,e,no);
int l = 0;
for(int i=s;i<=e;i++) if(no[i].x>=no[mid].x-ans&&no[i].x<=no[mid].x+ans)no2[l++] = no[i];
sort(no2,no2+l,cmpY);
for(int i=0;i<l;i++)
for(int j=i+1;j<l;j++)
{
if(no2[j].y-no2[i].y>=ans)break;
LL pre = dis(no2[i],no2[j]);
if(ans>pre)
{
ans = pre;
flag1 = no2[i].index;
flag2 = no2[j].index;
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
ans = ma;
scanf("%I64d",&n);
LL sum = 0;
for(int i=0;i<n;i++){scanf("%I64d %I64d",&no[i].x,&no[i].y);no[i].index = i;}
sort(no,no+n,cmpX);
closet(0,n-1,no);
sum+=ans*(n-2);
LL flag11 = flag1,flag22 = flag2;
int l=0;
ans = ma;
for(int i=0;i<n;i++) if(no[i].index!=flag11)no3[l++] = no[i];
closet(0,n-2,no3);
sum+=ans;
l = 0;
ans = ma;
for(int i=0;i<n;i++) if(no[i].index!=flag22)no3[l++] = no[i];
closet(0,n-2,no3);
sum+=ans;
printf("%I64d\n",sum);
}
return 0;
}