CF44G Shooting Gallery KDtree
我们考虑用靶子来匹配射击点,可以把靶子按 \(z\) 从小到大排序后,依次寻找范围内的编号最小的射击点,并将其删除,正确性显然。
考虑如何优化这个过程,实际上我们的操作分为两种:
\(1.\) 在二维平面内找编号最小的点。
\(2.\) 在二维平面内删除点。
可以把射击点建出 \(KDtree\) ,然后维护查询和删除 ,具体实现可以看代码。
#include<algorithm>
#include<iostream>
#include<cstdio>
#define lson tr[k].ls
#define rson tr[k].rs
using namespace std;
int n, m, root, cnt, nowk, ans;
const int N = 100010, inf = 1e8;
int fa[N], pos[N], Ans[N];
struct mb
{
int xl, yl, xr, yr, z, id;
friend bool operator <(const mb &a, const mb &b)
{return a.z < b.z;}
} B[N];
struct sj
{
int x, y, id;
friend bool operator <(const sj &a, const sj &b)
{return nowk ? a.x < b.x : a.y < b.y;}
} S[N];
struct shu
{
int mn, id, x, y, minx, miny, maxx, maxy, ls, rs;
} tr[N];
void pushup(int k)
{
tr[k].mn = tr[k].id;
if (lson)
{
tr[k].mn = min(tr[k].mn, tr[lson].mn);
tr[k].minx = min(tr[k].minx, tr[lson].minx); tr[k].miny = min(tr[k].miny, tr[lson].miny);
tr[k].maxx = max(tr[k].maxx, tr[lson].maxx); tr[k].maxy = max(tr[k].maxy, tr[lson].maxy);
}
if (rson)
{
tr[k].mn = min(tr[k].mn, tr[rson].mn);
tr[k].minx = min(tr[k].minx, tr[rson].minx); tr[k].miny = min(tr[k].miny, tr[rson].miny);
tr[k].maxx = max(tr[k].maxx, tr[rson].maxx); tr[k].maxy = max(tr[k].maxy, tr[rson].maxy);
}
}
void build(int FA, int &k, int l, int r, int KD)
{
if (l > r)return;
int mid = (l + r) >> 1; k = ++cnt; nowk = KD;
nth_element(S + l, S + mid, S + r + 1);
pos[S[mid].id] = k; fa[k] = FA;
tr[k].id = tr[k].mn = S[mid].id;
tr[k].x = tr[k].minx = tr[k].maxx = S[mid].x;
tr[k].y = tr[k].miny = tr[k].maxy = S[mid].y;
build(k, lson, l, mid - 1, KD ^ 1); build(k, rson, mid + 1, r, KD ^ 1);
pushup(k);
}
void ask(int k, int xl, int yl, int xr, int yr)
{
if (tr[k].maxx < xl || xr < tr[k].minx || tr[k].maxy < yl || yr < tr[k].miny)return;
if (xl <= tr[k].minx && tr[k].maxx <= xr && yl <= tr[k].miny && tr[k].maxy <= yr) {ans = min(ans, tr[k].mn); return;}
if (tr[k].id != inf && xl <= tr[k].x && tr[k].x <= xr && yl <= tr[k].y && tr[k].y <= yr) {ans = min(ans, tr[k].id);}
if (lson)ask(lson, xl, yl, xr, yr);
if (rson)ask(rson, xl, yl, xr, yr);
}
void shan(int x)
{
tr[x].id = inf;
while (x)
{
pushup(x);
x = fa[x];
}
}
int main()
{
cin >> n;
for (int i = 1, xl, xr, yl, yr, z; i <= n; ++i)
{
scanf("%d%d%d%d%d", &xl, &xr, &yl, &yr, &z);
B[i] = (mb) {xl, yl, xr, yr, z, i};
}
cin >> m;
for (int i = 1; i <= m; ++i)
scanf("%d%d", &S[i].x, &S[i].y), S[i].id = i;
build(0, root, 1, m, 0);
sort(B + 1, B + 1 + n);
for (int i = 1; i <= n; ++i)
{
ans = inf; ask(root, B[i].xl, B[i].yl, B[i].xr, B[i].yr);
if (ans != inf)
{
Ans[ans] = B[i].id;
shan(pos[ans]);
}
}
for (int i = 1; i <= m; ++i)printf("%d\n", Ans[i]);
return 0;
}