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];
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) { // O(nlogn)
    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++) {
            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", &p[i].y);
        p[i].x = i;
    }
    for(int i = 2; i <= n; i++) p[i].y += p[i - 1].y;
    sort(p + 1, p + n + 1, cmpx);
    printf("%lld\n", Merge(1, n));
    return 0;
}
posted @ 2020-08-22 19:19  Emcikem  阅读(104)  评论(0编辑  收藏  举报