【题目链接】
【思路要点】
- 将坐标系以原点为中心旋转一定角度,对圆心建立KDTree。
- 模拟题目中的过程,利用KDTree的子树信息进行剪枝。
- 最坏时间复杂度\(O(N^2)\),期望时间复杂度\(O(NLogN)\)。
【代码】
/*Double Version, Faster but Lower in Precision*/ #include<bits/stdc++.h> using namespace std; const int MAXN = 3e5 + 5; const double INF = 1e99; const double eps = 1e-2; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -f; for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } struct circle {double x, y; int r, home; }; struct range {double Maxx, Maxy, Minx, Miny; }; struct Node { int lc, rc, ans; circle info; range rng; } a[MAXN]; circle c[MAXN], now; int n, cmptype, root, size, home[MAXN]; inline bool outside(int root) { if (now.x + now.r < a[root].rng.Minx - eps || now.x - now.r > a[root].rng.Maxx + eps) return true; if (now.y + now.r < a[root].rng.Miny - eps || now.y - now.r > a[root].rng.Maxy + eps) return true; return false; } inline double sqr(const double x) {return x * x; } inline bool inside(int root) { double dist = sqr(now.x - a[root].info.x) + sqr(now.y - a[root].info.y); return dist <= sqr(now.r + a[root].info.r) + eps; } void update(int root) { if (a[root].ans == 0) { a[root].rng.Minx = a[root].info.x - a[root].info.r; a[root].rng.Maxx = a[root].info.x + a[root].info.r; a[root].rng.Miny = a[root].info.y - a[root].info.r; a[root].rng.Maxy = a[root].info.y + a[root].info.r; } else { a[root].rng.Minx = a[root].rng.Miny = INF; a[root].rng.Maxx = a[root].rng.Maxy = -INF; } if (a[root].lc != 0) { int tmp = a[root].lc; chkmax(a[root].rng.Maxx, a[tmp].rng.Maxx); chkmax(a[root].rng.Maxy, a[tmp].rng.Maxy); chkmin(a[root].rng.Minx, a[tmp].rng.Minx); chkmin(a[root].rng.Miny, a[tmp].rng.Miny); } if (a[root].rc != 0) { int tmp = a[root].rc; chkmax(a[root].rng.Maxx, a[tmp].rng.Maxx); chkmax(a[root].rng.Maxy, a[tmp].rng.Maxy); chkmin(a[root].rng.Minx, a[tmp].rng.Minx); chkmin(a[root].rng.Miny, a[tmp].rng.Miny); } } bool work(int root) { if (outside(root)) return false; bool used = false; if (a[root].ans == 0 && inside(root)) a[root].ans = now.home, used = true; if (a[root].lc) used |= work(a[root].lc); if (a[root].rc) used |= work(a[root].rc); if (used) update(root); return used; } bool cmp(const circle &a, const circle &b) { if (cmptype) { if (a.x == b.x) return a.y < b.y; else return a.x < b.x; } else { if (a.y == b.y) return a.x < b.x; else return a.y < b.y; } } bool cnp(const circle &a, const circle &b) { if (a.r == b.r) return a.home < b.home; else return a.r > b.r; } void build(int &root, int l, int r, bool type) { root = ++size; cmptype = type; int mid = (l + r) / 2; nth_element(c + l, c + mid, c + r + 1, cmp); a[root].info = c[mid]; home[c[mid].home] = root; if (mid > l) build(a[root].lc, l, mid - 1, type ^ true); if (mid < r) build(a[root].rc, mid + 1, r, type ^ true); update(root); } int main() { read(n); for (int i = 1; i <= n; i++) { read(c[i].x), read(c[i].y), read(c[i].r), c[i].home = i; double tmpx = c[i].x * 0.6 - c[i].y * 0.8; double tmpy = c[i].y * 0.6 + c[i].x * 0.8; c[i].x = tmpx, c[i].y = tmpy; } build(root, 1, n, true); sort(c + 1, c + n + 1, cnp); for (int i = 1; i <= n; i++) { if (a[home[c[i].home]].ans) continue; now = c[i]; work(root); } for (int i = 1; i <= n; i++) write(a[home[i]].ans), putchar(' '); return 0; } #include<bits/stdc++.h> using namespace std; const int MAXN = 3e5 + 5; const long double INF = 1e99; const long double eps = 1e-7; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -f; for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } struct circle {long double x, y; int r, home; }; struct range {long double Maxx, Maxy, Minx, Miny; }; struct Node { int lc, rc, ans; circle info; range rng; } a[MAXN]; circle c[MAXN], now; int n, cmptype, root, size, home[MAXN]; inline bool outside(int root) { if (now.x + now.r < a[root].rng.Minx - eps || now.x - now.r > a[root].rng.Maxx + eps) return true; if (now.y + now.r < a[root].rng.Miny - eps || now.y - now.r > a[root].rng.Maxy + eps) return true; return false; } inline long double sqr(const long double x) {return x * x; } inline bool inside(int root) { long double dist = sqr(now.x - a[root].info.x) + sqr(now.y - a[root].info.y); return dist <= sqr(now.r + a[root].info.r) + eps; } void update(int root) { if (a[root].ans == 0) { a[root].rng.Minx = a[root].info.x - a[root].info.r; a[root].rng.Maxx = a[root].info.x + a[root].info.r; a[root].rng.Miny = a[root].info.y - a[root].info.r; a[root].rng.Maxy = a[root].info.y + a[root].info.r; } else { a[root].rng.Minx = a[root].rng.Miny = INF; a[root].rng.Maxx = a[root].rng.Maxy = -INF; } if (a[root].lc != 0) { int tmp = a[root].lc; chkmax(a[root].rng.Maxx, a[tmp].rng.Maxx); chkmax(a[root].rng.Maxy, a[tmp].rng.Maxy); chkmin(a[root].rng.Minx, a[tmp].rng.Minx); chkmin(a[root].rng.Miny, a[tmp].rng.Miny); } if (a[root].rc != 0) { int tmp = a[root].rc; chkmax(a[root].rng.Maxx, a[tmp].rng.Maxx); chkmax(a[root].rng.Maxy, a[tmp].rng.Maxy); chkmin(a[root].rng.Minx, a[tmp].rng.Minx); chkmin(a[root].rng.Miny, a[tmp].rng.Miny); } } bool work(int root) { if (outside(root)) return false; bool used = false; if (a[root].ans == 0 && inside(root)) a[root].ans = now.home, used = true; if (a[root].lc) used |= work(a[root].lc); if (a[root].rc) used |= work(a[root].rc); if (used) update(root); return used; } bool cmp(const circle &a, const circle &b) { if (cmptype) { if (a.x == b.x) return a.y < b.y; else return a.x < b.x; } else { if (a.y == b.y) return a.x < b.x; else return a.y < b.y; } } bool cnp(const circle &a, const circle &b) { if (a.r == b.r) return a.home < b.home; else return a.r > b.r; } void build(int &root, int l, int r, bool type) { root = ++size; cmptype = type; int mid = (l + r) / 2; nth_element(c + l, c + mid, c + r + 1, cmp); a[root].info = c[mid]; home[c[mid].home] = root; if (mid > l) build(a[root].lc, l, mid - 1, type ^ true); if (mid < r) build(a[root].rc, mid + 1, r, type ^ true); update(root); } int main() { read(n); for (int i = 1; i <= n; i++) { read(c[i].x), read(c[i].y), read(c[i].r), c[i].home = i; long double tmpx = c[i].x * 0.6 - c[i].y * 0.8; long double tmpy = c[i].y * 0.6 + c[i].x * 0.8; c[i].x = tmpx, c[i].y = tmpy; } build(root, 1, n, true); sort(c + 1, c + n + 1, cnp); for (int i = 1; i <= n; i++) { if (a[home[c[i].home]].ans) continue; now = c[i]; work(root); } for (int i = 1; i <= n; i++) write(a[home[i]].ans), putchar(' '); return 0; } /*Long Double Version, Slower but Higher in Precision*/ #include<bits/stdc++.h> using namespace std; const int MAXN = 3e5 + 5; const long double INF = 1e99; const long double eps = 1e-5; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -f; for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } struct circle {long double x, y; int r, home; }; struct range {long double Maxx, Maxy, Minx, Miny; }; struct Node { int lc, rc, ans; circle info; range rng; } a[MAXN]; circle c[MAXN], now; int n, cmptype, root, size, home[MAXN]; inline bool outside(int root) { if (now.x + now.r < a[root].rng.Minx - eps || now.x - now.r > a[root].rng.Maxx + eps) return true; if (now.y + now.r < a[root].rng.Miny - eps || now.y - now.r > a[root].rng.Maxy + eps) return true; return false; } inline long double sqr(const long double x) {return x * x; } inline bool inside(int root) { long double dist = sqr(now.x - a[root].info.x) + sqr(now.y - a[root].info.y); return dist <= sqr(now.r + a[root].info.r) + eps; } void update(int root) { if (a[root].ans == 0) { a[root].rng.Minx = a[root].info.x - a[root].info.r; a[root].rng.Maxx = a[root].info.x + a[root].info.r; a[root].rng.Miny = a[root].info.y - a[root].info.r; a[root].rng.Maxy = a[root].info.y + a[root].info.r; } else { a[root].rng.Minx = a[root].rng.Miny = INF; a[root].rng.Maxx = a[root].rng.Maxy = -INF; } if (a[root].lc != 0) { int tmp = a[root].lc; chkmax(a[root].rng.Maxx, a[tmp].rng.Maxx); chkmax(a[root].rng.Maxy, a[tmp].rng.Maxy); chkmin(a[root].rng.Minx, a[tmp].rng.Minx); chkmin(a[root].rng.Miny, a[tmp].rng.Miny); } if (a[root].rc != 0) { int tmp = a[root].rc; chkmax(a[root].rng.Maxx, a[tmp].rng.Maxx); chkmax(a[root].rng.Maxy, a[tmp].rng.Maxy); chkmin(a[root].rng.Minx, a[tmp].rng.Minx); chkmin(a[root].rng.Miny, a[tmp].rng.Miny); } } bool work(int root) { if (outside(root)) return false; bool used = false; if (a[root].ans == 0 && inside(root)) a[root].ans = now.home, used = true; if (a[root].lc) used |= work(a[root].lc); if (a[root].rc) used |= work(a[root].rc); if (used) update(root); return used; } bool cmp(const circle &a, const circle &b) { if (cmptype) { if (a.x == b.x) return a.y < b.y; else return a.x < b.x; } else { if (a.y == b.y) return a.x < b.x; else return a.y < b.y; } } bool cnp(const circle &a, const circle &b) { if (a.r == b.r) return a.home < b.home; else return a.r > b.r; } void build(int &root, int l, int r, bool type) { root = ++size; cmptype = type; int mid = (l + r) / 2; nth_element(c + l, c + mid, c + r + 1, cmp); a[root].info = c[mid]; home[c[mid].home] = root; if (mid > l) build(a[root].lc, l, mid - 1, type ^ true); if (mid < r) build(a[root].rc, mid + 1, r, type ^ true); update(root); } int main() { read(n); for (int i = 1; i <= n; i++) { read(c[i].x), read(c[i].y), read(c[i].r), c[i].home = i; long double tmpx = c[i].x * 0.6 - c[i].y * 0.8; long double tmpy = c[i].y * 0.6 + c[i].x * 0.8; c[i].x = tmpx, c[i].y = tmpy; } build(root, 1, n, true); sort(c + 1, c + n + 1, cnp); for (int i = 1; i <= n; i++) { if (a[home[c[i].home]].ans) continue; now = c[i]; work(root); } for (int i = 1; i <= n; i++) write(a[home[i]].ans), putchar(' '); return 0; }