【kd-tree】天使玩偶SJY摆棋子

it2026-01-12  9

题目

展开 题目描述 Ayu 在七年前曾经收到过一个天使玩偶,当时她把它当作时间囊埋在了地下。而七年后 的今天,Ayu 却忘了她把天使玩偶埋在了哪里,所以她决定仅凭一点模糊的记忆来寻找它。

我们把 Ayu 生活的小镇看作一个二维平面坐标系,而 Ayu 会不定时地记起可能在某个点 (xmy) 埋下了天使玩偶;或者 Ayu 会询问你,假如她在 (x,y)(x,y),那么她离近的天使玩偶可能埋下的地方有多远。

因为 Ayu 只会沿着平行坐标轴的方向来行动,所以在这个问题里我们定义两个点之间的距离为 \operatorname{dist}(A,B)=|A_x-B_x|+|A_y-B_y|dist(A,B)=∣A x ​ −B x ​ ∣+∣A y ​ −B y ​ ∣。其中 A_xA x ​ 表示点 AA 的横坐标,其余类似。

输入格式 第一行包含两个整数 nn 和 mm,在刚开始时,Ayu 已经知道有 nn 个点可能埋着天使玩偶, 接下来 Ayu 要进行 mm 次操作

接下来 nn 行,每行两个非负整数 (x_i,y_i)(x i ​ ,y i ​ ),表示初始 nn 个点的坐标。

再接下来 mm 行,每行三个非负整数 t,x_i,y_it,x i ​ ,y i ​ 。

如果 t=1t=1,则表示 Ayu 又回忆起了一个可能埋着玩偶的点 (x_i,y_i)(x i ​ ,y i ​ )。 如果 t=2t=2,则表示 Ayu 询问如果她在点 (x_i,y_i)(x i ​ ,y i ​ ),那么在已经回忆出来的点里,离她近的那个点有多远 输出格式 对于每个 t=2t=2 的询问,在单独的一行内输出该询问的结果。

输入输出样例 输入 #1复制 2 3 1 1 2 3 2 1 2 1 3 3 2 4 2 输出 #1复制 1 2 说明/提示 数据规模与约定 对于 100%100% 的数据 保证 1 \leq n,m\leq 3 \times 10^51≤n,m≤3×10 5 ,0 \leq x_i,y_i \leq 10^60≤x i ​ ,y i ​ ≤10 6 。

思路

kd-tree 这题是要求曼哈顿距离,另外封在结构体里的那个,求的是当前结点,到以该结点为根的子树维护矩形边界的最小曼哈顿距离。

代码

#include<bits/stdc++.h> #define alpha (0.75) using namespace std; const int N = 6e5 + 5; const int INF = 0x3f3f3f3f; bool dimension; bool reg_dimension; int n,m,ans; struct Point { int x,y; Point(int X = 0,int Y = 0) :x(X) ,y(Y) {} }; Point a[N]; struct Node *null; struct Node { int cover; Point p,r1,r2; Node *son[2]; void maintain() { r1.x = min(r1.x,min(son[0]->r1.x,son[1]->r1.x)) ; r1.y = min(r1.y,min(son[0]->r1.y,son[1]->r1.y)) ; r2.x = max(r2.x,max(son[0]->r2.x,son[1]->r2.x)) ; r2.y = max(r2.y,max(son[0]->r2.y,son[1]->r2.y)) ; cover = son[0]->cover + son[1]->cover + 1; } bool is_bad() { return max(son[0]->cover,son[1]->cover) > cover*alpha + 5; } int dis(Point p) { if(this == null) return INF; int res = 0; if(p.x<r1.x || p.x>r2.x) res += p.x < r1.x ? r1.x - p.x : p.x - r2.x; if(p.y<r1.y || p.y>r2.y) res += p.y < r1.y ? r1.y - p.y : p.y - r2.y; return res; } }; Node mempool[N]; Node *tail; Node *root; bool cmp(Point p1,Point p2) { if(dimension == 0) return p1.x < p2.x || (p1.x == p2.x && p1.y < p2.y) ; return p1.y < p2.y || (p1.y == p2.y && p1.x < p2.x) ; } int Manhattan_dis(Point a,Point b) { return abs(a.x - b.x) + abs(a.y - b.y) ; } void init() { tail = mempool; null = tail++; null->son[0] = null->son[1] = null; null->r1 = Point(INF,INF) ; null->r2 = Point(-INF,-INF) ; null->cover = 0; root = null; } Node* new_node(Point key) { Node *o; o = tail++; o->son[0] = o->son[1] = null; o->cover= 1; o->p = o->r1 = o->r2 = key; return o; } void travel(Node* p,vector<Node*>&x) { if(p == null) return; travel(p->son[0],x) ; x.push_back(p) ; travel(p->son[1],x) ; } Node* divide(vector<Node*>&x,int l,int r,bool d) { if(l >= r) return null; int mid = (l + r) >> 1; dimension = d; Node *o = x[mid]; o->son[0] = divide(x,l,mid,d ^ 1) ; o->son[1] = divide(x,mid + 1,r,d ^ 1) ; o->maintain() ; return o; } void rebuild(Node *&o,bool d) { static vector<Node*>v; v.clear() ; travel(o,v) ; o = divide(v,0,v.size() ,d) ; } Node* build(int l,int r,bool d) { if(l >= r) return null; int mid = (l + r) >> 1; dimension = d; nth_element(a + l,a + mid,a + r,cmp) ; Node *o = new_node(a[mid]) ; o->son[0] = build(l,mid,d ^ 1) ; o->son[1] = build(mid + 1,r,d ^ 1) ; o->maintain() ; return o; } Node** __insert(Node *&o,Point key) { if(o == null) { o = new_node(key) ; reg_dimension = dimension; return &null; } else { o->cover++; bool dir = cmp(key,o->p) ^ 1; dimension ^= 1; Node** res = __insert(o->son[dir],key) ; if(o->is_bad()) { res = &o; reg_dimension = dimension; } o->maintain() ; return res; } } void insert(Point key) { reg_dimension = dimension = 0; Node** res = __insert(root,key) ; if(*res != null) rebuild(*res,reg_dimension) ; } void query(Node *o,Point key) { if(o == null) return; ans = min(ans,Manhattan_dis(key,o->p)) ; int dir = o->son[0]->dis(key) > o->son[1]->dis(key) ; query(o->son[dir],key) ; if(o->son[dir ^ 1]->dis(key) < ans) query(o->son[dir ^ 1],key) ; } int main() { init() ; n = read() ; m = read() ; for(int i = 0; i < n; i++) a[i].x = read() ,a[i].y = read() ; root = build(0,n,0) ; while(m--) { int op = read() ,x = read() ,y = read() ; if(op == 1) insert(Point(x,y)) ; else { ans = INF; query(root,Point(x,y)) ; printf("%d\n",ans) ; } } return 0; }
最新回复(0)