1. 程式人生 > 實用技巧 >cf 429D Tricky Function - 平面最近點對

cf 429D Tricky Function - 平面最近點對

傳送門
平面最近點對模型
給出平面上n個點,找出其中一對點的距離,使得在這n個點的所有點對中,該距離為所有點對中最小的
分治法求
\(g(i,j)\)就是求區間[i + 1, j]的區間的值,也就是字首和表示\(sum[j] - sum[i]\)
那麼轉換為\((j - i) ^ 2 + (sum[j] - sum[i]) ^ 2\)
那麼對於n個點,x就是i,y就是字首和

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#define ll long long
using namespace std;
const int N = 1e6 + 5;
const ll Inf = 1e13;
struct Point {
    ll x, y;
    Point (int X = 0, int Y = 0) { x = X, y = Y;}
} p[N], Q[N];
int tot = 0;
bool cmpx(Point a, Point b) {return a.x < b.x || (a.x == b.x && a.y < b.y);}
bool cmpy(Point a, Point b) {return a.y < b.y;}
ll dis(Point a, Point b) {
    return pow(a.x - b.x, 2) + pow(a.y - b.y, 2);
}
ll Merge(int l, int r) {
    ll ans = Inf;
    if (l == r) return ans;
    if (l + 1 == r) return dis(p[l], p[r]);
    int mid = (l + r) / 2;
    ll d1 = Merge(l, mid);
    ll d2 = Merge(mid + 1, r);
    ans = min(d1, d2);
    ll d = sqrt(ans);
    int k = 0;
    for (int i = mid; i >= l; i --) {
        if (p[mid].x - p[i].x > d) break;
        Q[++k] = p[i];
    }
    for (int i = mid + 1; i <= r; i ++) {
        if (p[i].x - p[mid].x > d) break;
        Q[++k] = p[i];
    }
    sort(Q + 1, Q + k + 1, cmpy);
    for (int i = 1; i < k; i ++) {
        for (int j = i + 1 ; j <= k && Q[j].y - Q[i].y <= d; j ++) {
            tot++; ans = min(ans, dis(Q[i], Q[j]));
        }
    }
    return ans;
}
int main() {
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) {
        scanf("%lld%lld", &p[i].x, &p[i].y);
    }
    sort(p + 1, p + n + 1, cmpx);
    printf("%lld\n", Merge(1, n));
    return 0;
}