POJ3714 Raid
Description
After successive failures in the battles against the Union, the Empire retreated to its last stronghold. Depending on its powerful defense system, the Empire repelled the six waves of Union's attack. After several sleepless nights of thinking, Arthur, General of the Union, noticed that the only weakness of the defense system was its energy supply. The system was charged by \(N\) nuclear power stations and breaking down any of them would disable the system.
The general soon started a raid to the stations by \(N\) special agents who were paradroped into the stronghold. Unfortunately they failed to land at the expected positions due to the attack by the Empire Air Force. As an experienced general, Arthur soon realized that he needed to rearrange the plan. The first thing he wants to know now is that which agent is the nearest to any power station. Could you, the chief officer, help the general to calculate the minimum distance between an agent and a station?
Input
The first line is a integer \(T\) representing the number of test cases.
Each test case begins with an integer \(N (1 \leq N \leq 100000)\).
The next \(N\) lines describe the positions of the stations.
Each line consists of two integers\(X (0 \leq X \leq 1000000000)\) and $Y (0 \leq Y \leq 1000000000) $indicating the positions of the station.
The next following \(N\) lines describe the positions of the agents.
Each line consists of two integers \(X (0 \leq X \leq 1000000000)\) and \(Y (0 \leq Y \leq 1000000000)\) indicating the positions of the agent.
Output
For each test case output the minimum distance with precision of three decimal placed in a separate line.
吐槽时间
千万不要在vjudge上交这道题!千万不要在vjudge上交这道题!千万不要在vjudge上交这道题!
先说一下本人惨痛的心路历程。。先在vjudge上看到这题。。感觉像是KDtree。。。然后百度。。发现密密麻麻的一片都是二分。。点开几篇。。觉得复杂度有点假。。于是开始自己苟KDtree。。
苟完之后,一交!果然WA了。。。发现是自己估价函数写错了。。。改完。。再交。。WA×2。。开始网上扒题解对拍。。。一拍秒WA。。发现自己的估价函数再一次写错。。。
这次改完之后。不敢急着交。。先对拍,直到拍到一万多组数据都没有出错。。自信提交。。。WA×3
觉得不可理解。。扒来数据本机测试。。。AC。。
POJ上一交。。AC!vjudge上一交。。WA!
总感觉vjudge在针对我的KDtree。。。。。
Solution
现在开始一本正经讲题解。。 其实会KDtree的话这道题是一眼题。。直接将n个点建立一颗KDtree,后\(n\)个点直接在KDtree上找最近的点即可,复杂度$ O(n\sqrt{n}) $
注意当距离为欧几里得距离求最近点时。。要合理设计估价函数(其实是我菜,其他的直接看代码吧。。
Code
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int T,n,root,D;
struct node
{
long long mn[2],mx[2],d[2];
int l,r;
}t[100010];
long long Mn;
long long sqr(long long x)
{
return x*x;
}
inline bool cmp(node a,node b)
{
return (a.d[D]<b.d[D] || (a.d[D]==b.d[D] && a.d[!D]<b.d[!D]));
}
void updata(int f,int s)
{
t[f].mn[0]=min(t[f].mn[0],t[s].mn[0]);
t[f].mn[1]=min(t[f].mn[1],t[s].mn[1]);
t[f].mx[0]=max(t[f].mx[0],t[s].mx[0]);
t[f].mx[1]=max(t[f].mx[1],t[s].mx[1]);
}
void up(int x)
{
if (t[x].l) updata(x,t[x].l);
if (t[x].r) updata(x,t[x].r);
}
int build(int l,int r,int d)
{
int mid=(l+r)>>1;
D=d;
nth_element(t+l,t+mid,t+r+1,cmp);
t[mid].mx[0]=t[mid].mn[0]=t[mid].d[0];
t[mid].mx[1]=t[mid].mn[1]=t[mid].d[1];
if (l!=mid) t[mid].l=build(l,mid-1,!d);
if (r!=mid) t[mid].r=build(mid+1,r,!d);
up(mid);
return mid;
}
long long get_dis(int p,int x,int y)
{
long long X=0,Y=0;
if (x<t[p].mn[0]) X=t[p].mn[0]-x;
if (x>t[p].mx[0]) X=x-t[p].mx[0];
if (y<t[p].mn[1]) Y=t[p].mn[1]-y;
if (y>t[p].mx[1]) Y=y-t[p].mx[1];
return X*X+Y*Y;
}
void query(int p,int x,int y)
{
long long dl=get_dis(t[p].l,x,y),dr=get_dis(t[p].r,x,y);
if (!t[p].l) dl=2e18;
if (!t[p].r) dr=2e18;
long long disnow=sqr(t[p].d[0]-x)+sqr(t[p].d[1]-y);
if (disnow<Mn) Mn=disnow;
if (dl<dr)
{
if (dl<Mn && t[p].l) query(t[p].l,x,y);
if (dr<Mn && t[p].r) query(t[p].r,x,y);
}
else
{
if (dr<Mn && t[p].r) query(t[p].r,x,y);
if (dl<Mn && t[p].l) query(t[p].l,x,y);
}
}
int main()
{
scanf("%d",&T);
while (T--)
{
long long ans=2e18;
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%lld%lld",&t[i].d[0],&t[i].d[1]);
t[i].mn[0]=t[i].mx[0]=t[i].d[0];
t[i].mn[1]=t[i].mx[1]=t[i].d[1];
t[i].l=t[i].r=0;
}
root=build(1,n,0);
for (int i=1;i<=n;i++)
{
int x,y;
Mn=2e18;
scanf("%d%d",&x,&y);
query(root,x,y);
if (Mn<ans) ans=Mn;
}
printf("%.3lf\n",sqrt(ans+0.));
}
return 0;
}