Log^2的cdq分治怎么也跑不过。优化常数优化到底了也不行。所以kd大法好。
怎么都觉得kd树就一暴力+剪枝=log。
思想就是先按x二分,然后再按y二分,然后再按x二分。然后这玩意比较像平衡树,中间那个点是要代表一个真实的结点的而不是一个值。然后insert的时候感觉复杂度完全没有保证啊。如果要保证可能要替罪羊一类的东西吧。虽然这题好像不用保证。
询问的时候就更迷了,就是估计一个离哪边近,然后先搜。然后另一边如果估计值还小于答案就再搜一遍。好诡异,时间复杂度是怎么来的。
然后代码略丑,加了zhx式读入优化后长度xxxxx。
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
using namespace std;
#define READ_OPTIMIZE
#ifdef READ_OPTIMIZE
/*int _d_;
#define readInt(_s_) {\
_s_ = 0;\
while (!isdigit(_d_ = getchar()));\
while ((_s_ = _s_ * 10 + _d_ - 48), isdigit(_d_ = getchar()));\
}*/
const int BUF_SIZE = 30;
char buf[BUF_SIZE], *buf_s = buf, *buf_t = buf + 1;
#define PTR_NEXT() \
{ \
buf_s ++; \
if (buf_s == buf_t) \
{ \
buf_s = buf; \
buf_t = buf + fread(buf, 1, BUF_SIZE, stdin); \
} \
}
#define readInt(_n_) \
{ \
while (*buf_s != '-' && !isdigit(*buf_s)) \
PTR_NEXT(); \
bool register _nega_ = false; \
if (*buf_s == '-') \
{ \
_nega_ = true; \
PTR_NEXT(); \
} \
int register _x_ = 0; \
while (isdigit(*buf_s)) \
{ \
_x_ = _x_ * 10 + *buf_s - '0'; \
PTR_NEXT(); \
} \
if (_nega_) \
_x_ = -_x_; \
(_n_) = (_x_); \
}
#else
#define readInt(_s_) (scanf("%d",&_s_));
#endif
#define min(_a_,_b_) (((_a_)<(_b_))?(_a_):(_b_))
#define max(_a_,_b_) (((_a_)>(_b_))?(_a_):(_b_))
struct point {
int x, y, t;
};
struct kdnode {
int x, y;
int l, r, u, d;
kdnode *ls, *rs;
kdnode() {
ls = 0, rs = 0;
}
};
const int maxn = 1000009;
const int maxnd = maxn;
const int inf = 0x3f3f3f3f;
inline bool cmpx(const point& a, const point& b) {
return a. x < b. x;
}
inline bool cmpy(const point& a, const point& b) {
return a. y < b. y;
}
int m, n;
point a[maxn], b[maxn];
kdnode *sp, nlst[maxnd];
inline void update(kdnode*& p) {
p-> l = p-> x;
p-> r = p-> x;
p-> d = p-> y;
p-> u = p-> y;
if (p-> ls) {
if (p-> ls-> l < p-> l)
p-> l = p-> ls-> l;
if (p-> ls-> r > p-> r)
p-> r = p-> ls-> r;
if (p-> ls-> d < p-> d)
p-> d = p-> ls-> d;
if (p-> ls-> u > p-> u)
p-> u = p-> ls-> u;
}
if (p-> rs) {
if (p-> rs-> l < p-> l)
p-> l = p-> rs-> l;
if (p-> rs-> r > p-> r)
p-> r = p-> rs-> r;
if (p-> rs-> d < p-> d)
p-> d = p-> rs-> d;
if (p-> rs-> u > p-> u)
p-> u = p-> rs-> u;
}
}
kdnode *kdBuild(int l, int r, int dr = 1) {
if (l >= r)
return 0;
int mid = (l + r) >> 1;
kdnode *p = sp ++;
if (dr)
nth_element(a + l, a + mid, a + r, cmpx);
else
nth_element(a + l, a + mid, a + r, cmpy);
p-> x = a[mid]. x;
p-> y = a[mid]. y;
p-> ls = kdBuild(l, mid, dr ^ 1);
p-> rs = kdBuild(mid + 1, r, dr ^ 1);
update(p);
return p;
}
inline int guessDist(kdnode* p, int x, int y) {
int ans = 0;
if (x > p-> r)
ans += x - p-> r;
else if (x < p-> l)
ans += p-> l - x;
if (y > p-> u)
ans += y - p-> u;
else if (y < p-> d)
ans += p-> d - y;
return ans;
}
void kdQry(kdnode* p, int x, int y, int& ans) {
int dl, dr, d = abs(x - p-> x) + abs(y - p-> y);
if (d < ans)
ans = d;
if (p-> ls)
dl = guessDist(p-> ls, x, y);
else
dl = inf;
if (p-> rs)
dr = guessDist(p-> rs, x, y);
else
dr = inf;
if (dl < dr) {
if (dl < ans)
kdQry(p-> ls, x, y, ans);
if (dr < ans)
kdQry(p-> rs, x, y, ans);
}
else {
if (dr < ans)
kdQry(p-> rs, x, y, ans);
if (dl < ans)
kdQry(p-> ls, x, y, ans);
}
}
kdnode* kdIns(kdnode* p, int x, int y, int dr = 1) {
if (!p) {
p = sp ++;
p-> x = x;
p-> y = y;
p-> ls = 0;
p-> rs = 0;
}
else {
if (dr) {
if (x < p-> x)
p-> ls = kdIns(p-> ls, x, y, dr ^ 1);
else
p-> rs = kdIns(p-> rs, x, y, dr ^ 1);
}
else {
if (y < p-> y)
p-> ls = kdIns(p-> ls, x, y, dr ^ 1);
else
p-> rs = kdIns(p-> rs, x, y, dr ^ 1);
}
}
update(p);
return p;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
readInt(m);
readInt(n);
for (int i = 0; i < m; ++ i) {
readInt(a[i]. x);
readInt(a[i]. y);
a[i]. t = 0;
}
for (int i = 0; i < n; ++ i) {
readInt(b[i]. t);
readInt(b[i]. x);
readInt(b[i]. y);
}
sp = nlst;
kdnode *rt = kdBuild(0, m);
for (int i = 0; i < n; ++ i)
if (b[i]. t == 2) {
int ans = inf;
kdQry(rt, b[i]. x, b[i]. y, ans);
printf("%d\n", ans);
}
else
rt = kdIns(rt, b[i]. x, b[i]. y);
}