BZOJ2716 天使玩偶
之前写过CDQ + 线段树的, 被惨烈地卡常卡了下来...
所以决定改写KD-tree
这里先放个代码占个坑, 后面再写教程吧.
#include <cstdio>
#include <cctype>
#include <algorithm>
#include <climits>
#include <cmath>
namespace Zeonfai
{
inline int getInt()
{
int a = 0, sgn = 1;
char c;
while(! isdigit(c = getchar()))
if(c == '-')
sgn *= -1;
while(isdigit(c))
a = a * 10 + c - '0', c = getchar();
return a * sgn;
}
inline void _print(int a)
{
if(! a)
return;
_print(a / 10);
putchar('0' + a % 10);
}
inline void println(int a)
{
if(a < 0)
putchar('-'), a *= -1;
if(! a)
putchar('0');
_print(a);
putchar('\n');
}
}
const int N = (int)5e5, M = (int)5e5;
int n, m;
int dmn;
struct point
{
int x, y;
inline point() {}
inline point(int _x, int _y)
{
x = _x, y = _y;
}
inline int friend operator <(const point &a, const point &b)
{
if(dmn == 0)
return a.x < b.x;
else
return a.y < b.y;
}
};
point pos[N + M];
struct KDtree
{
struct node
{
node *suc[2];
point p, bnd[2];
inline node(const point &_p)
{
bnd[0] = bnd[1] = p = _p, suc[0] = suc[1] = NULL;
}
inline void update()
{
bnd[0] = bnd[1] = p;
for(int i = 0; i < 2; ++ i)
if(suc[i] != NULL)
{
bnd[0].x = std::min(suc[i]->bnd[0].x, bnd[0].x), bnd[0].y = std::min(suc[i]->bnd[0].y, bnd[0].y);
bnd[1].x = std::max(suc[i]->bnd[1].x, bnd[1].x), bnd[1].y = std::max(suc[i]->bnd[1].y, bnd[1].y);
}
}
};
node *rt;
node* build(int L, int R, int D)
{
if(L > R)
return NULL;
int mid = L + R >> 1;
dmn = D;
std::nth_element(pos + L, pos + mid, pos + R + 1);
node *u = new node(pos[mid]);
u->suc[0] = build(L, mid - 1, D ^ 1);
u->suc[1] = build(mid + 1, R, D ^ 1);
u->update();
return u;
}
inline void build()
{
rt = build(0, n - 1, 0);
}
node* insert(node *u, const point &p, int D)
{
if(u == NULL)
{
u = new node(p);
return u;
}
dmn = D;
if(p < u->p)
u->suc[0] = insert(u->suc[0], p, D ^ 1);
else
u->suc[1] = insert(u->suc[1], p, D ^ 1);
u->update();
return u;
}
inline void insert(const point &p)
{
rt = insert(rt, p, 0);
}
int ans;
inline int getDistance(const point &a, const point &b)
{
return abs(a.x - b.x) + abs(a.y - b.y);
}
inline int getDistance(const point &p, node *u)
{
if(u == NULL)
return INT_MAX;
int res = 0;
if(p.x < u->bnd[0].x || p.x > u->bnd[1].x)
res += p.x < u->bnd[0].x ? u->bnd[0].x - p.x : p.x - u->bnd[1].x;
if(p.y < u->bnd[0].y || p.y > u->bnd[1].y)
res += p.y < u->bnd[0].y ? u->bnd[0].y - p.y : p.y - u->bnd[1].y;
return res;
}
void query(node *u, const point &p)
{
if(u == NULL)
return;
ans = std::min(ans, getDistance(p, u->p));
int k = getDistance(p, u->suc[0]) > getDistance(p, u->suc[1]);
if(getDistance(p, u->suc[k]) < ans)
query(u->suc[k], p);
if(getDistance(p, u->suc[k ^ 1]) < ans)
query(u->suc[k ^ 1], p);
}
inline int query(const point &p)
{
ans = INT_MAX;
query(rt, p);
return ans;
}
}KDT;
int main()
{
#ifndef ONLINE_JUDGE
freopen("BZOJ2716.in", "r", stdin);
freopen("BZOJ2716KDT.out", "w", stdout);
#endif
using namespace Zeonfai;
n = getInt(), m = getInt();
for(int i = 0; i < n; ++ i)
pos[i].x = getInt(), pos[i].y = getInt();
KDT.build();
while(m --)
{
int tp = getInt(), x = getInt(), y = getInt();
if(tp == 1)
KDT.insert(pos[n ++] = point(x, y));
else
println(KDT.query(point(x, y)));
}
}