Brief description:
给定平面上的一组点集 ,对于每个询问,输出一个新的点,查询所有距离她最近的点的编号。
(点集规模 N <= 100000, 询问次数 M <= 10000)
Analysis:
.. .
Naive:
const int N = 100009; Po P[N], cur; int n, m; int main() { //freopen("in.txt", "r", stdin); REP_C(i, _RD(n)){ scanf("%lf %lf", &P[i].x, &P[i].y); } DO_C(RD()){ scanf("%lf %lf", &cur.x, &cur.y); DB d = INF; REP(i, n) checkMin(d, dist_sqr(cur, P[i])); REP(i, n) if (d == dist_sqr(cur, P[i])) printf("%d ", i + 1); puts(""); } }
….
Hash:
Data Structure:
... int random(int l, int r){ return rand() % (r - l + 1) + l; } struct Rec: Po{ int id; }; const int N = 100009; const int NN = N; /* | 1|0 ----- 3|2 | */ Rec node[NN]; DB xl[NN], xr[NN], yl[NN], yr[NN]; int c[NN][4], root, total; // Point Quadtree .. . Rec P[N], temp; Po cur; DB d; VI L; int n, m; inline int Dir(Po a, Po b){ return a.x < b.x ? (a.y < b.y ? 3 : 1) : (a.y < b.y ? 2 : 0); } inline int Rev(int dir){ return dir ^ 3; } void Insert(int &now = root){ if (!now) now = ++total, node[now] = temp; else Insert(c[now][Dir(temp, node[now])]); } void Cut(int now, int parent){ if (!now) return; if (node[now].x < node[parent].x) xl[now] = xl[parent], xr[now] = node[parent].x; else xl[now] = node[parent].x, xr[now] = xr[parent]; if (node[now].y < node[parent].y) yl[now] = yl[parent], yr[now] = node[parent].y; else yl[now] = node[parent].y, yr[now] = yr[parent]; REP(i, 4) Cut(c[now][i], now); } void Update(Rec item){ DB dd = dist_sqr(cur, item); if (sgn(dd, d) <= 0){ if (sgn(dd, d) == -1) d = dd, CLR(L); L.PB(item.id); } } void Find(int now = root){ if (!now) return; if (xl[now] <= cur.x && cur.x <= xr[now]){ if (cur.y <= yl[now]) if (sgn(d, sqr(yl[now] - cur.y)) < 0) return; if (yr[now] <= cur.y) if (sgn(d, sqr(cur.y - yr[now])) < 0) return; } else if (yl[now] <= cur.y && cur.y <= yr[now]){ if (cur.x <= xl[now]) if (sgn(d, sqr(xl[now] - cur.x)) < 0) return; if (xr[now] <= cur.x) if (sgn(d, sqr(cur.x - xr[now])) < 0) return; } else if (sgn(d, min(sqr(xl[now] - cur.x), sqr(xr[now] - cur.x)) + min(sqr(yl[now] - cur.y), sqr(yr[now] - cur.y))) < 0) return; int dir = Dir(cur, node[now]); Find(c[now][dir]), Update(node[now]); if (dir == 0 || dir == 3) Find(c[now][1]), Find(c[now][2]); else if (dir == 1 || dir == 2) Find(c[now][0]), Find(c[now][3]); } int main() { //freopen("in.txt", "r", stdin); REP_C(i, _RD(n)){ scanf("%lf %lf", &P[i].x, &P[i].y); P[i].id = i + 1; } srand((unsigned)time(NULL)); REP(i, n) swap(P[i], P[random(i, n - 1)]); REP(i, n) temp = P[i], Insert(); xl[root] = yl[root] = -10000, xr[root] = yr[root] = 10000; REP(i, 4) Cut(c[root][i], root); DO_C(RD()){ scanf("%lf %lf", &cur.x, &cur.y), CLR(L), d = INF; Find(); SRT(L); REP(i, SZ(L) - 1) printf("%d ", L[i]); printf("%d\n", L[SZ(L)-1]); } }
... int random(int l, int r){ return rand() % (r - l + 1) + l; } struct Rec: Po{ int id; }; const int N = 100009; const int NN = N; Rec node[NN]; DB xl[NN], xr[NN], yl[NN], yr[NN]; int c[NN][2], root, total; // 2-d tree .. . Rec P[N], temp; Po cur; DB d; VI L; int n, m; inline int Dir(int level, Po a, Po b){ if (level&1) return a.x < b.x ? 0 : 1; else return a.y < b.y ? 0 : 1; } inline int Rev(int dir){ return dir ^ 1; } void Insert(int &now = root, int level = 0){ if (!now) now = ++total, node[now] = temp; else Insert(c[now][Dir(level, temp, node[now])], level + 1); } void Cut(int now, int parent, int level){ if (!now) return; if (level&1){ if (node[now].x < node[parent].x) xl[now] = xl[parent], xr[now] = node[parent].x; else xl[now] = node[parent].x, xr[now] = xr[parent]; yl[now] = yl[parent], yr[now] = yr[parent]; } else { if (node[now].y < node[parent].y) yl[now] = yl[parent], yr[now] = node[parent].y; else yl[now] = node[parent].y, yr[now] = yr[parent]; xl[now] = xl[parent], xr[now] = xr[parent]; } REP(i, 2) Cut(c[now][i], now, level + 1); } void Update(Rec item){ DB dd = dist_sqr(cur, item); if (sgn(dd, d) <= 0){ if (sgn(dd, d) == -1) d = dd, CLR(L); L.PB(item.id); } } void Find(int now = root, int level = 0){ if (!now || sgn(d, ((xl[now] <= cur.x && cur.x <= xr[now]) ? 0. : min(sqr(cur.x - xl[now]), sqr(cur.x - xr[now]))) + ((yl[now] <= cur.y && cur.y <= yr[now]) ? 0. : min(sqr(cur.y - yl[now]), sqr(cur.y - yr[now])))) < 0) return; int dir = Dir(level, cur, node[now]); Find(c[now][dir], level + 1), Update(node[now]); Find(c[now][Rev(dir)], level + 1); } int main() { //freopen("in.txt", "r", stdin); REP_C(i, _RD(n)){ scanf("%lf %lf", &P[i].x, &P[i].y); P[i].id = i + 1; } //srand((unsigned)time(NULL)); REP(i, n) swap(P[i], P[random(i, n - 1)]); REP(i, n) temp = P[i], Insert(); xl[root] = yl[root] = -10000, xr[root] = yr[root] = 10000; REP(i, 2) Cut(c[root][i], root, 0); DO_C(RD()){ scanf("%lf %lf", &cur.x, &cur.y), CLR(L), d = INF; Find(); SRT(L); REP(i, SZ(L) - 1) printf("%d ", L[i]); printf("%d\n", L[SZ(L)-1]); } }
Vonoir Graph:
Reference:
The Design and Analysis of Spatial Data Structures[Hanan][Samet]
External links:
http://acm.timus.ru/problem.aspx?space=1&num=1369
http://en.wikipedia.org/wiki/Nearest_neighbor_search