Problem
www.lydsy.com/JudgeOnline/problem.php?id=2648
vjudge.net/contest/187908#problem/D
Meaning
棋盘上有 n 个黑子,有 m 个操作,每次可以:
- 放一个黑子;
- 或放一个白子,顺便查询离与它曼哈顿距离最近的黑子的曼哈顿距离
Analysis
对前面的 n 个点常规地建一棵 K-D树,对后来的黑子就插入,白子只查询最近距离而不查询。
Code
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 500000, M = 500000, D = 2, BIG = 0x7f7f7f7f;
int idx;
struct node
{
int v[D];
bool operator < (const node &rhs) const
{
return v[idx] < rhs.v[idx];
}
} kdt[N+M], aim;
int big[N+M][D], sml[N+M][D], lc[N+M], rc[N+M];
void pushup(int p)
{
for(int i = 0; i < D; ++i)
{
int &b = big[p][i], &s = sml[p][i];
if(~lc[p])
{
b = max(b, big[lc[p]][i]);
s = min(s, sml[lc[p]][i]);
}
if(~rc[p])
{
b = max(b, big[rc[p]][i]);
s = min(s, sml[rc[p]][i]);
}
}
}
int build(int l, int r, int d)
{
idx = d & 1;
int m = l + r >> 1;
nth_element(kdt + l, kdt + m, kdt + r + 1);
lc[m] = rc[m] = -1;
for(int i = 0; i < D; ++i)
big[m][i] = sml[m][i] = kdt[m].v[i];
if(l < m)
lc[m] = build(l, m - 1, d + 1);
if(r > m)
rc[m] = build(m + 1, r, d + 1);
pushup(m);
return m;
}
int sz;
int add()
{
int p = sz++;
lc[p] = rc[p] = -1;
for(int i = 0; i < D; ++i)
big[p][i] = sml[p][i] = kdt[p].v[i] = aim.v[i];
return p;
}
/* 插入黑子 */
void insert(int rt, int d)
{
idx = d & 1;
if(aim < kdt[rt]) // 分到左子树的区域
if(~lc[rt])
insert(lc[rt], d + 1);
else
lc[rt] = add();
else // 分到右子树的区域
if(~rc[rt])
insert(rc[rt], d + 1);
else
rc[rt] = add();
pushup(rt);
}
int manhattan(int p)
{
return abs(aim.v[0] - kdt[p].v[0]) +
abs(aim.v[1] - kdt[p].v[1]);
}
int evaluate(int p)
{
int res = 0;
for(int i = 0; i < D; ++i)
if(aim.v[i] > big[p][i])
res += aim.v[i] - big[p][i];
else if(aim.v[i] < sml[p][i])
res += sml[p][i] - aim.v[i];
return res;
}
int ans;
void query(int rt)
{
ans = min(ans, manhattan(rt));
int dl = BIG, dr = BIG;
if(~lc[rt])
dl = evaluate(lc[rt]);
if(~rc[rt])
dr = evaluate(rc[rt]);
if(dl < dr)
{
if(dl < ans)
query(lc[rt]);
if(dr < ans)
query(rc[rt]);
}
else
{
if(dr < ans)
query(rc[rt]);
if(dl < ans)
query(lc[rt]);
}
}
int main()
{
int n, m;
scanf("%d%d", &n, &m);
for(int i = 0; i < n; ++i)
for(int j = 0; j < D; ++j)
scanf("%d", &kdt[i].v[j]);
int rt = build(0, n - 1, 0);
sz = n;
for(int i = 0, t; i < m; ++i)
{
scanf("%d%d%d", &t, &aim.v[0], &aim.v[1]);
if(t == 1)
insert(rt, 0);
else
{
ans = BIG;
query(rt);
printf("%d\n", ans);
}
}
return 0;
}