1. 程式人生 > >「LuoguP1429」 平面最近點對(加強版)

「LuoguP1429」 平面最近點對(加強版)

urn dig tchar return article ron sdi nbsp git

題目描述

給定平面上n個點,找出其中的一對點的距離,使得在這n個點的所有點對中,該距離為所有點對中最小的

輸入輸出格式

輸入格式:

第一行:n;2≤n≤200000

接下來n行:每行兩個實數:x y,表示一個點的行坐標和列坐標,中間用一個空格隔開。

輸出格式:

僅一行,一個實數,表示最短距離,精確到小數點後面4位。

輸入輸出樣例

輸入樣例#1: 復制
3
1 1
1 2
2 2
輸出樣例#1: 復制
1.0000

說明

0<=x,y<=10^9

題解

考場清晰的記得以前聽過,並且記錯做法還覺得自己是天才......

考場思路:按橫軸排序,然後從左往右枚舉每個點,把和該點的橫坐標之差小於$ans$的點暴力算。

然後怕構造數據被卡(很多個點的橫坐標差不多,豎軸差很多的話可以卡成$N$方),於是考慮用權值線段樹優化豎軸,也就是從權值線段樹中取豎軸在當前點加減ans範圍的點暴力算。(考試$x,y$範圍1e6)

這樣應該就不會T了......

然後毒瘤評測人只給64M啊!哪裏夠開權值線段樹啊!

於是把掃描線轉了45°(也可以理解為把紙轉45°),再做類暴力,這樣就不好卡了。

然後就過了2333

 1 /*
 2     qwerta
 3     P1429 平面最近點對(加強版)
 4     Accepted
 5     100
 6     代碼 C++,1.16KB
7 提交時間 2018-10-19 15:55:35 8 耗時/內存 9 348ms, 2064KB 10 */ 11 #include<algorithm> 12 #include<iostream> 13 #include<cstdio> 14 #include<cmath> 15 using namespace std; 16 #define R register 17 inline int read() 18 { 19 char ch=getchar(); 20 int x=0;
21 while(!isdigit(ch))ch=getchar(); 22 while(isdigit(ch)){x=x*10+ch-0;ch=getchar();} 23 return x; 24 } 25 const int MAXN=200000+3,MAXX=1000000+3; 26 struct emm{ 27 int x,y; 28 }a[MAXN]; 29 const double k=-0.5; 30 bool cmp(emm qaq,emm qwq) 31 { 32 return qaq.y-k*qaq.x<qwq.y-k*qwq.x; 33 } 34 inline double dis(int u,int v) 35 { 36 return sqrt(1LL*(a[u].x-a[v].x)*(a[u].x-a[v].x)+1LL*(a[u].y-a[v].y)*(a[u].y-a[v].y)); 37 } 38 double gen2=sqrt(2); 39 inline double je(int u,int v) 40 { 41 return abs(((a[u].y-k*a[u].x)-(a[v].y-k*a[v].x)))/gen2; 42 } 43 int main() 44 { 45 //freopen("dark.in","r",stdin); 46 //freopen("dark.out","w",stdout); 47 int n=read(); 48 for(R int i=1;i<=n;++i) 49 a[i].x=read(),a[i].y=read(); 50 sort(a+1,a+n+1,cmp); 51 int l=1,r=1; 52 double ans=dis(1,2); 53 for(R int u=1;u<=n;++u) 54 { 55 while(je(u,l)>ans)++l; 56 while(je(r+1,u)<ans&&r<n)++r; 57 //cout<<u<<" "<<l<<" "<<r<<endl; 58 for(R int v=l;v<=r;++v) 59 if(u!=v) 60 ans=min(ans,dis(u,v)); 61 } 62 printf("%.4f",ans); 63 return 0; 64 }

「LuoguP1429」 平面最近點對(加強版)