题目大意
一堆点,可以加点,询问离某个点曼哈顿距离最近的点的曼哈顿距离
Solution
离线做法:cdq分治,代码量蛮短的
这里主要讲在线做法
这是k-d tree的模板题,但是因为有加点操作,所以不能保证k-dtree的重量平衡,可能会使这棵BST的结构变得很难看,随便一卡就能卡掉
所以我们要加上Scapegoat tree来暴力维护它的相对平衡
Code
#include <cstdio>
#include <iostream>
#include <algorithm>
#define al 0.75
#define N 1000010
#define INF 0x3f3f3f3f
using namespace std;
int rub[N], WD, top, root, cur, ans;
struct Point {
int x[2];
Point(int X = 0, int Y = 0) {
x[0] = X;
x[1] = Y;
}
inline bool operator < (const Point &o) const {
return x[WD] < o.x[WD];
}
}p[N];
struct Node {
int mi[2], mx[2], ls, rs, sz;
Point p;
}tr[N];
inline int read() {
char ch = getchar();
int x = 0;
while (!isdigit(ch)) ch = getchar();
while (isdigit(ch)) {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x;
}
inline int newNode() {
if (top) return rub[top--];
return ++cur;
}
inline void pushup(int k) {
int l = tr[k].ls, r = tr[k].rs;
for (int i = 0; i < 2; ++i) {
tr[k].mi[i] = tr[k].mx[i] = tr[k].p.x[i];
if (l) {
tr[k].mi[i] = min(tr[k].mi[i], tr[l].mi[i]);
tr[k].mx[i] = max(tr[k].mx[i], tr[l].mx[i]);
}
if (r) {
tr[k].mi[i] = min(tr[k].mi[i], tr[r].mi[i]);
tr[k].mx[i] = max(tr[k].mx[i], tr[r].mx[i]);
}
}
tr[k].sz = tr[l].sz + tr[r].sz + 1;
}
inline int build(int l, int r, int wd) {
if (l > r) return 0;
int k = newNode(), mid = l + r >> 1;
WD = wd;
nth_element(p + l, p + mid, p + r + 1);
tr[k].p = p[mid];
tr[k].ls = build(l, mid - 1, wd ^ 1);
tr[k].rs = build(mid + 1, r, wd ^ 1);
pushup(k);
return k;
}
inline void pia(int k, int num) {
if (tr[k].ls) pia(tr[k].ls, num);
p[num + tr[tr[k].ls].sz + 1] = tr[k].p;
rub[++top] = k;
if (tr[k].rs) pia(tr[k].rs, num + tr[tr[k].ls].sz + 1);
}
inline void check(int &k, int wd) {
if (al * tr[k].sz < tr[tr[k].ls].sz || al * tr[k].sz < tr[tr[k].rs].sz) {
pia(k, 0);
k = build(1, tr[k].sz, wd);
}
}
inline void ins(Point now, int &k, int wd) {
if (!k) {
k = newNode();
tr[k].p = now;
tr[k].ls = tr[k].rs = 0;
pushup(k);
return;
}
if (tr[k].p.x[wd] < now.x[wd]) ins(now, tr[k].rs, wd ^ 1);
else ins(now, tr[k].ls, wd ^ 1);
pushup(k);
check(k, wd);
}
inline int getdis(Point now, int k) {
int ret = 0;
for (int i = 0; i < 2; ++i) {
ret += max(0, now.x[i] - tr[k].mx[i]) + max(0, tr[k].mi[i] - now.x[i]);
}
return ret;
}
inline int dis(Point a, Point b) {
return abs(a.x[0] - b.x[0]) + abs(a.x[1] - b.x[1]);
}
inline void query(Point now, int k) {
ans = min(ans, dis(now, tr[k].p));
int dl = INF, dr = INF;
if (tr[k].ls) dl = getdis(now, tr[k].ls);
if (tr[k].rs) dr = getdis(now, tr[k].rs);
if (dl < dr) {
if (dl < ans) query(now, tr[k].ls);
if (dr < ans) query(now, tr[k].rs);
}
else {
if (dr < ans) query(now, tr[k].rs);
if (dl < ans) query(now, tr[k].ls);
}
}
int main() {
int n = read(), m = read();
for (int i = 1; i <= n; ++i) {
p[i].x[0] = read();
p[i].x[1] = read();
}
root = build(1, n, 0);
while(m--) {
int opt = read(), x = read(), y = read();
if (opt == 1) ins(Point(x, y), root, 0);
else ans = INF, query(Point(x, y), root), printf("%d\n", ans);
}
return 0;
}