本蒟蒻先想了一个naive的(O(nlog^3{n}))做法。
看到求最小值可以想到先二分答案,然后用一个“集体二分”(我也不知道是什么鬼就是一起做二分,然后每个询问的二分上下界都不同)的方法可以一起二分,二分到一个答案后只需统计这个范围内有没有点即可。这时我们可以把曼哈顿距离转成切比雪夫距离,然后就套一个cdq的模板就做完了。可以证明每次cdq的时间复杂度为 (O(nlog^2{n})),然后外层有 (O(log{n})) 次循环,所以总时间复杂度为耻辱的 (O(nlog^3{n}))。
显然是过不去的。考虑换一种思路,不二分。
这时处理曼哈顿距离的第二种套路:拆绝对值。加上偏序关系后就可以把绝对值拆开了,对应四种关系,对于每种用一个cdq来求即可。这里cdq不再是计数,而是统计一个最大值,具体看代码。
这里还是举个栗子:假设我们拆开是这样的 (|x1-x2|+|y1-y2|=(x1+y1)-(x2+y2)),那么我们只需维护 (x2+y2) 的最大值即可。这个用树状数组也可以维护。
考虑其他偏序关系,只需改变偏序关系即可(不用搞什么坐标轴旋转一坨迷惑行为)。
这题卡常,所以最好把O2带上(我也不知道O2为什么会快这么多)。
#include <bits/stdc++.h>
using namespace std;
const int MAXV = 1000010;
const int inf = 0x3f3f3f3f;
struct node{
int x, y, val, id, ans;
}p[1000005], tmp[1000005], q[1000005];
int ans[1000005];
int n, m, tot, cnt;
int BIT[1000055];
int dx[5] = {0, 1, 1, -1, -1};
int dy[5] = {0, 1, -1, 1, -1};
int ask(int x) {
int ret = -inf;
while (x) {
ret = max(ret, BIT[x]);
x -= (x & (-x));
}
return ret;
}
void add(int x, int v) {
while (x <= MAXV) {
BIT[x] = max(BIT[x], v);
x += (x & (-x));
}
}
void del(int x) {
while (x <= MAXV) {
BIT[x] = -inf;
x += (x & (-x));
}
}
bool cmp(int id, int x1, int x2) {
if (id <= 2) return x1 > x2;
return x1 < x2;
}
void cdq(int id, int l, int r) {
if (l == r) return;
int mid = (l + r) >> 1;
cdq(id, l, mid); cdq(id, mid + 1, r);
int i = l, j = mid + 1, top = 0;
while (i <= mid && j <= r) {
if (cmp(id, p[i].x, p[j].x)) {
if (id & 1) p[j].ans = min(p[j].ans, p[j].x * dx[id] + p[j].y * dy[id] - ask(p[j].y + 1));
else p[j].ans = min(p[j].ans, p[j].x * dx[id] + p[j].y * dy[id] - ask(MAXV - p[j].y - 1));
tmp[++top] = p[j++];
} else {
if (!p[i].val) {
tmp[++top] = p[i++];
continue;
}
if (id & 1) add(p[i].y + 1, p[i].x * dx[id] + p[i].y * dy[id]);
else add(MAXV - p[i].y - 1, p[i].x * dx[id] + p[i].y * dy[id]);
tmp[++top] = p[i++];
}
}
while (i <= mid) {
if (!p[i].val) {
tmp[++top] = p[i++];
continue;
}
if (id & 1) add(p[i].y + 1, p[i].x * dx[id] + p[i].y * dy[id]);
else add(MAXV - p[i].y - 1, p[i].x * dx[id] + p[i].y * dy[id]);
tmp[++top] = p[i++];
}
while (j <= r) {
if (id & 1) p[j].ans = min(p[j].ans, p[j].x * dx[id] + p[j].y * dy[id] - ask(p[j].y + 1));
else p[j].ans = min(p[j].ans, p[j].x * dx[id] + p[j].y * dy[id] - ask(MAXV - p[j].y - 1));
tmp[++top] = p[j++];
}
for (int now = l; now <= mid; now++) {
if (!p[now].val) continue;
if (id & 1) del(p[now].y + 1);
else del(MAXV - p[now].y - 1);
}
for (int now = 1; now <= top; now++) p[l + now - 1] = tmp[now];
}
int main() {
memset(BIT, -inf, sizeof(BIT));
memset(ans, inf, sizeof(ans));
scanf("%d%d", &n, &m); tot = n;
for (int i = 1; i <= n; i++) scanf("%d%d", &p[i].x, &p[i].y), p[i].val = 1;
while (m--) {
int opt, x, y;
scanf("%d%d%d", &opt, &x, &y);
if (opt == 1) p[++tot] = node{x, y, 1, 0, 0};
else p[++tot] = node{x, y, 0, ++cnt, 0};
}
for (int i = 1; i <= tot; i++) p[i].ans = inf;
for (int i = 1; i <= tot; i++) q[i] = p[i];
cdq(1, 1, tot);
for (int i = 1; i <= tot; i++) ans[p[i].id] = min(ans[p[i].id], p[i].ans);
for (int i = 1; i <= tot; i++) p[i] = q[i];
cdq(2, 1, tot);
for (int i = 1; i <= tot; i++) ans[p[i].id] = min(ans[p[i].id], p[i].ans);
for (int i = 1; i <= tot; i++) p[i] = q[i];
cdq(3, 1, tot);
for (int i = 1; i <= tot; i++) ans[p[i].id] = min(ans[p[i].id], p[i].ans);
for (int i = 1; i <= tot; i++) p[i] = q[i];
cdq(4, 1, tot);
for (int i = 1; i <= tot; i++) ans[p[i].id] = min(ans[p[i].id], p[i].ans);
for (int i = 1; i <= cnt; i++) printf("%d
", ans[i]);
return 0;
}