链接:

https://www.acwing.com/problem/content/121/

题意:

在与联盟的战斗中屡战屡败后,帝国撤退到了最后一个据点。

依靠其强大的防御系统,帝国击退了联盟的六波猛烈进攻。

经过几天的苦思冥想,联盟将军亚瑟终于注意到帝国防御系统唯一的弱点就是能源供应。

该系统由N个核电站供应能源,其中任何一个被摧毁都会使防御系统失效。

将军派出了N个特工进入据点之中,打算对能源站展开一次突袭。

不幸的是,由于受到了帝国空军的袭击,他们未能降落在预期位置。

作为一名经验丰富的将军,亚瑟很快意识到他需要重新安排突袭计划。

他现在最想知道的事情就是哪个特工距离其中任意一个发电站的距离最短。

你能帮他算出来这最短的距离是多少吗?

思路:

考虑n个点的情况, 排序后处理中点,计算左右两边到中点的最小值,再处理中点左右两边最小值范围内的所有点.

代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5+10;
struct Node
{
    int x, y;
    int op;
}a[MAXN], b[MAXN];
int n;

bool cmp(Node l, Node r)
{
    if (l.x == r.x)
        return l.y < r.y;
    return l.x < r.x;
}

bool cmp1(Node l, Node r)
{
    if (l.y == r.y)
        return l.x < r.x;
    return l.y < r.y;
}

double Getlen(Node l, Node r)
{
    if (l.op == r.op)
        return 1e9;
    double dx = l.x-r.x, dy = l.y-r.y;
    return sqrt(dx*dx+dy*dy);
}

double Sovle(int l, int r)
{
    int mid = (l+r)/2;
    if (l == r)
        return 1e9;
    if (r-l == 1)
        return Getlen(a[l], a[r]);
    double ans = min(Sovle(l, mid), Sovle(mid+1, r));
    int cnt = 0;
    for (int i = l;i <= r;i++)
    {
        if (a[i].x >= a[mid].x-ans && a[i].x <= a[mid].x+ans)
            b[++cnt] = a[i];
    }
    sort(b+1, b+1+cnt, cmp1);
    for (int i = 1;i <= cnt;i++)
    {
        for (int j = i+1;j <= cnt;j++)
        {
            if (b[j].y > b[i].y+ans)
                break;
            ans = min(ans, Getlen(a[i], a[j]));
        }
    }
    return ans;
}

int main()
{
    int t;
    scanf("%d", &t);
    while (t--)
    {
        scanf("%d", &n);
        for (int i = 1;i <= n;i++)
            scanf("%d%d", &a[i].x, &a[i].y), a[i].op = 0;
        for (int i = n+1;i <= 2*n;i++)
            scanf("%d%d", &a[i].x, &a[i].y), a[i].op = 1;
        n *= 2;
        sort(a+1, a+1+n, cmp);
        printf("%.3lf\n", Sovle(1, n));
    }

    return 0;
}