BestCoder 2nd Anniversary Palace

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值