【思路要点】
- 旋转坐标系,将曼哈顿距离转化为切比雪夫距离。
- 则我们需要求出一个包含尽可能多的点的正方形。
- 枚举正方形的右边界,用双指针维护左边界,线段树维护其中包含点数最多的区间即可。
- 时间复杂度 O ( N L o g N ) O(NLogN) O(NLogN) 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 3e5 + 5; typedef long long ll; typedef long double ld; typedef unsigned long long ull; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } struct SegmentTree { struct Node { int lc, rc; int tag, Max; } a[MAXN * 2]; int n, size, root; void update(int root) { a[root].Max = max(a[a[root].lc].Max, a[a[root].rc].Max); } void build(int &root, int l, int r) { root = ++size; a[root].Max = a[root].tag = 0; if (l == r) return; int mid = (l + r) / 2; build(a[root].lc, l, mid); build(a[root].rc, mid + 1, r); } void init(int x) { n = x; root = size = 0; build(root, 1, n); } void pushdown(int root) { if (a[root].tag == 0) return; a[a[root].lc].Max += a[root].tag; a[a[root].lc].tag += a[root].tag; a[a[root].rc].Max += a[root].tag; a[a[root].rc].tag += a[root].tag; a[root].tag = 0; } void modify(int root, int l, int r, int ql, int qr, int k) { if (l == ql && r == qr) { a[root].tag += k; a[root].Max += k; return; } pushdown(root); int mid = (l + r) / 2; if (mid >= ql) modify(a[root].lc, l, mid, ql, min(qr, mid), k); if (mid + 1 <= qr) modify(a[root].rc, mid + 1, r, max(mid + 1, ql), qr, k); update(root); } void modify(int l, int r, int k) { modify(root, 1, n, l, r, k); } int query(int root, int l, int r, int ql, int qr) { if (l == ql && r == qr) return a[root].Max; pushdown(root); int ans = 0, mid = (l + r) / 2; if (mid >= ql) ans = max(ans, query(a[root].lc, l, mid, ql, min(mid, qr))); if (mid + 1 <= qr) ans = max(ans, query(a[root].rc, mid + 1, r, max(mid + 1, ql), qr)); return ans; } int query(int l, int r) { if (l > r) return 0; else return query(root, 1, n, l, r); } } ST; set <int> st; int n, m, d, pos[MAXN], lft[MAXN]; map <int, int> home; pair <int, int> a[MAXN]; int main() { read(n), read(d); for (int i = 1; i <= n; i++) { int x, y; read(x), read(y); a[i] = make_pair(x + y, x - y); } sort(a + 1, a + n + 1); for (int i = 1; i <= n; i++) st.insert(a[i].second); for (auto x : st) { pos[++m] = x; home[x] = m; } for (int i = 1, j = 1; i <= m; i++) { while (pos[j] < pos[i] - d) j++; lft[i] = j; } ST.init(m); int ans = 0; for (int i = 1, j = 1; i <= n; i++) { int tmp = home[a[i].second]; ST.modify(lft[tmp], tmp, 1); while (a[j].first < a[i].first - d) { tmp = home[a[j++].second]; ST.modify(lft[tmp], tmp, -1); } chkmax(ans, ST.query(1, m)); } writeln(ans); return 0; }