Problem Description
棋盘上原本有,n个黑棋。
有两种操作:
1 x y 插入一个黑色棋子
2 x y 输出距离这个白色棋子最近的黑色棋子距离(这里的距离是曼哈顿距离)
思路:
参考ldq大佬博客
K-D树,其实就是一个k维的搜索树。这道题k = 2而已。
#include<bits/stdc++.h>
using namespace std;
const int DIM = 2;//维度,题目是二维
const int inf = 0x3f3f3f3f;
const int MAX = 500005;
struct node
{
int l, r;
int cd[DIM], maxn[DIM], minn[DIM];//分别代表坐标,以这个结点的为根的子树每一维最大值,和每一维最小值
inline void maintain()//初始化
{
l = r = 0;
for(int i = 0; i < DIM; i++)
maxn[i] = minn[i] = cd[i];
}
}tree[2*MAX];
int D;//第几维
bool operator < (const node &a, const node &b)//重载从小到大
{
return a.cd[D] < b.cd[D];
}
inline void Merge(int mid)//归并,也就是向上更新
{
//主要就是为了更新该结点maxn[], minn[]
int son[2] = {tree[mid].l, tree[mid].r};
for(int i = 0; i < 2; i++)
{
if(!son[i]) continue;
for(int j = 0; j < DIM; j++)
{
tree[mid].maxn[j] = max(tree[mid].maxn[j], tree[son[i]].maxn[j]);
tree[mid].minn[j] = min(tree[mid].minn[j], tree[son[i]].minn[j]);
}
}
}
int build(int l, int r, int now)//建树
{
int mid = (l+r)>>1;
D = now;
nth_element(tree+l, tree+mid, tree+r+1);//D维时,以mid这点为中点,左小 右大
tree[mid].maintain();//初始化
if(l < mid) tree[mid].l = build(l, mid-1, (now+1)%DIM);
if(r > mid) tree[mid].r = build(mid+1, r, (now+1)%DIM);
Merge(mid);//归并,向上更新
return mid;
}
int partionMin(int o, int k)//求k这个点,到o这个子树所有点,可能的最小距离值
{
int red = 0;
for(int i = 0; i < DIM; i++)
{
if(tree[k].cd[i] > tree[o].maxn[i]) red += tree[k].cd[i] - tree[o].maxn[i];
if(tree[k].cd[i] < tree[o].minn[i]) red += tree[o].minn[i] - tree[k].cd[i];
}
return red;
}
int ans;
void Query(int o, int k)//查找距离k这个点最近的距离
{
int dm = abs(tree[o].cd[0] - tree[k].cd[0]) + abs(tree[o].cd[1] - tree[k].cd[1]);//曼哈顿距离
if(ans > dm) ans = dm;//更新
int dl = tree[o].l ? partionMin(tree[o].l, k) : inf;//如果左子树存在就求k这个点,到tree[o].l这个子树所有点,可能的最小距离值。否则无穷
int dr = tree[o].r ? partionMin(tree[o].r, k) : inf;//
if(dl < dr)//目的优化时间复杂度
{
if(dl < ans) Query(tree[o].l, k);
if(dr < ans) Query(tree[o].r, k);
}
else
{
if(dr < ans) Query(tree[o].r, k);
if(dl < ans) Query(tree[o].l, k);
}
}
void Insert(int &o, int k, int now)//插入操作
{
if(o == 0)//代表到叶子结点的儿子
{
o = k;//更新就好了
return ;
}
if(tree[k].cd[now] < tree[o].cd[now]) Insert(tree[o].l, k, (now+1)%DIM);
else Insert(tree[o].r, k, (now+1)%DIM);
Merge(o);
}
int main()
{
int n, m, i, j;
while(~scanf("%d %d", &n, &m))
{
for(i = 1; i <= n; i++)
for(j = 0; j < DIM; j++)
scanf("%d", &tree[i].cd[j]);
int pos = n + 1;
int root = build(1, n, 0);
int op;
while(m--)
{
scanf("%d", &op);
for(j = 0; j < DIM; j++) scanf("%d", &tree[pos].cd[j]);
if(op == 1)
{
tree[pos].maintain();
Insert(root, pos, 0);
pos++;
}
else
{
ans = inf;
Query(root, pos);
printf("%d\n", ans);
}
}
}
}