HDU 2966 KDtree模板

来源:互联网 发布:网民网络素养教育工作 编辑:程序博客网 时间:2024/05/27 19:25

题意:

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2966
求每个点到最近邻点的距离平方


思路:

KDtree板子


代码:

// x维数为2的KDtree模板#include <bits/stdc++.h>using namespace std;typedef long long LL;const LL INF = 0x3f3f3f3f3f3f3f3f;const int MAXN = 1e5 + 10;struct Node {    int lson, rson;    LL Min[2], Max[2], x[2];    int id;} kdt[MAXN << 1], tmp;int root, cmp_x;LL ans, xx0, xx1;bool cmp (const Node &a, const Node &b) {    return a.x[cmp_x] < b.x[cmp_x] || (a.x[cmp_x] == b.x[cmp_x] && a.x[cmp_x^1] < b.x[cmp_x^1]);}// 更新每个结点的边界信息void pushUp(int u, int v) {    for (int i = 0; i < 2; i++) kdt[u].Min[i] = min(kdt[u].Min[i], kdt[v].Min[i]);    for (int i = 0; i < 2; i++) kdt[u].Max[i] = max(kdt[u].Max[i], kdt[v].Max[i]);}int kdtBuild(int l, int r, int X) {    int mid = (l + r) >> 1;    kdt[mid].lson = kdt[mid].rson = 0;    cmp_x = X;    nth_element(kdt + l + 1, kdt + mid + 1, kdt + r + 1, cmp); // 将编号为mid的元素放在中间,比它小的放在前面,比它大的放后面    kdt[mid].Min[0] = kdt[mid].Max[0] = kdt[mid].x[0];    kdt[mid].Min[1] = kdt[mid].Max[1] = kdt[mid].x[1];    if (l != mid) kdt[mid].lson = kdtBuild(l, mid - 1, X ^ 1);    if (r != mid) kdt[mid].rson = kdtBuild(mid + 1, r, X ^ 1);    if (kdt[mid].lson) pushUp(mid, kdt[mid].lson);    if (kdt[mid].rson) pushUp(mid, kdt[mid].rson);    return mid;}// 插入新的结点void kdtInsert(int now) {    int X = 0, p = root;    while (true) {        pushUp(p, now);        if (kdt[now].x[X] < kdt[p].x[X]) {            if (!kdt[p].lson) {                kdt[p].lson = now;                return;            }            else p = kdt[p].lson;        }        else {            if (!kdt[p].rson) {                kdt[p].rson = now;                return;            }            else p = kdt[p].rson;        }    }}// 点(x,y)在结点id的边界范围内能得到的最大距离上界LL getMaxDis(int id, LL x0, LL x1) {    LL res = 0;    if (x0 < kdt[id].Min[0]) res += (kdt[id].Min[0] - x0) * (kdt[id].Min[0] - x0);    if (x0 > kdt[id].Max[0]) res += (kdt[id].Max[0] - x0) * (kdt[id].Max[0] - x0);    if (x1 < kdt[id].Min[1]) res += (kdt[id].Min[1] - x1) * (kdt[id].Min[1] - x1);    if (x1 > kdt[id].Max[1]) res += (kdt[id].Max[1] - x1) * (kdt[id].Max[1] - x1);    return res;}LL dist(int id, LL x0, LL x1) {    return (kdt[id].x[0] - x0) * (kdt[id].x[0] - x0) + (kdt[id].x[1] - x1) * (kdt[id].x[1] - x1);}void kdtQuery(int p) {    LL dl = INF, dr = INF, d;    d = dist(p, xx0, xx1);    if (kdt[p].x[0] == xx0 && kdt[p].x[1] == xx1) d = INF;  // 查询(x,y)时要将(x,y)到自己的距离设为INF    ans = min(ans, d);    if (kdt[p].lson) dl = getMaxDis(kdt[p].lson, xx0, xx1);    if (kdt[p].rson) dr = getMaxDis(kdt[p].rson, xx0, xx1);    if (dl < dr) {        if (dl < ans) kdtQuery(kdt[p].lson);        if (dr < ans) kdtQuery(kdt[p].rson);    }    else {        if (dr < ans) kdtQuery(kdt[p].rson);        if (dl < ans) kdtQuery(kdt[p].lson);    }}LL answer[MAXN];int main() {    //freopen("in.txt", "r", stdin);    int T;    scanf("%d", &T);    while (T--) {        int n;        scanf("%d", &n);        for (int i = 1; i <= n; i++) {            scanf("%I64d%I64d", &kdt[i].x[0], &kdt[i].x[1]);            kdt[i].id = i;        }        root = kdtBuild(1, n, 0);        for (int i = 1; i <= n; i++) {            ans = INF;            xx0 = kdt[i].x[0]; xx1 = kdt[i].x[1];            kdtQuery(root);            answer[kdt[i].id] = ans;           // printf("---%d\n", ans);        }        for (int i = 1; i <= n; i++)            printf("%I64d\n", answer[i]);    }    return 0;}
原创粉丝点击