BestCoder 2nd Anniversary D hdu 5721 最近点对



链接:戳这里


Palace
 Time Limit: 8000/4000 MS (Java/Others)   Memory Limit: 262144/262144 K (Java/Others)
问题描述
为了寻找失去的爱人Cupid,Psyche需要完成Venus的最后一项任务:前往冥界,收集一盒冥界皇后Prosperina的美貌。

冥界有 n个神殿,可以表示为平面上的 n个整点。Psyche想要找到这 n座神殿中,最近的两座神殿之间的距离。传说那就是通往主殿的密码。

但是冥界神秘莫测,在不同的时刻,这 n 座神殿中的某一座会消失。

Psyche想要知道,对于 n 座神殿中的任意一座消失的情况,最近的两座神殿之间的距离。你只需要输出它们的和。

为避免精度误差,定义两点 (x​1 ,y1​​ ),(x​2​​ ,y​2​​ )间的距离为 d=(x​1​​ −x​2)​^2​​ +(y​1​​ −y​2​​ )^​2​​ 。
输入描述
第一行,一个整数 T (1≤T≤5),代表数据组数。

对于每组数据,第一行,一个整数 n (3≤n≤10e​5),代表神殿个数。

下面 n 行,每行两个整数 x, y  (−10e​5≤x,y≤10e​5),代表神殿的位置在 (x,y)。

注意可能存在两座神殿坐落在同一位置。
输出描述
输出 T 行,对于每组数据,输出 n 座神殿中的任意一座消失的情况,最近两座神殿之间的距离的和。
输入样例
1
3
0 0
1 1
2 2
输出样例
12
Hint
神殿 (0,0)消失时,  d=(1−2)^2 +(1−2)^2 =2;

神殿 (1,1)消失时, d=(0−2)^​2+(0−2)^​2 =8;

神殿 (2,2)消失时, d = (0-1) ^ 2 + (0-1) ^ 2 = 2 

故答案为 2 + 8 + 2 = 12。


思路:

最近的那对点对可以贡献n-2次,然后就是分别删掉两点中的一点算贡献


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<iomanip>
#include<cmath>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
#define maxn 0x3f3f3f3f
#define MAX 1000100
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
typedef unsigned long long ull;
#define INF (1ll<<60)-1
using namespace std;
struct point{
    ll x,y;
    bool operator <(const point &a)const{
        if(x==a.x) return y<a.y;
        return x<a.x;
    }
}s[100100];
typedef pair<ll ,pair<int,int> > Pair;
Pair calc(int i,int j){
    ll ans=(s[i].x-s[j].x)*(s[i].x-s[j].x)+(s[i].y-s[j].y)*(s[i].y-s[j].y);
    return make_pair(ans,make_pair(i,j));
}
int p[100100];
bool cmpy(int a,int b){
    return s[a].y<s[b].y;
}
Pair Dis(int l,int r){
    Pair tmp;
    if(l+1==r) return calc(l,r);
    if(l+2==r){
        Pair t1=calc(l,r);
        Pair t2=calc(l,l+1);
        Pair t3=calc(l+1,r);
        tmp=min(t1,min(t2,t3));
        return tmp;
    }
    int mid=(l+r)/2;
    Pair d1=Dis(l,mid);
    Pair d2=Dis(mid+1,r);
    tmp=min(d1,d2);
    int cnt=0;
    for(int i=l;i<=r;i++){
        if((s[mid].x-s[i].x)*(s[mid].x-s[i].x)<tmp.first) p[cnt++]=i;
    }
    sort(p,p+cnt,cmpy);
    for(int i=0;i<cnt;i++){
        for(int j=i+1;j<cnt;j++){
            int u=p[i],v=p[j];
            if((s[v].y-s[u].y)*(s[v].y-s[u].y)>tmp.first) break;
            Pair d3=calc(u,v);
            tmp=min(tmp,d3);
        }
    }
    return tmp;
}
int main(){
    int T,n;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        for(int i=0;i<n;i++) scanf("%I64d%I64d",&s[i].x,&s[i].y);
        sort(s,s+n);
        Pair d=Dis(0,n-1);
        ll ans=d.first*(n-2);
        swap(s[d.second.first],s[n-1]);
        ans+=Dis(0,n-2).first;
        swap(s[d.second.first],s[n-1]);
        swap(s[d.second.second],s[n-1]);
        ans+=Dis(0,n-2).first;
        printf("%I64d\n",ans);
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值