【省内训练2019-06-04】团

【思路要点】

  • 旋转坐标系,将曼哈顿距离转化为切比雪夫距离。
  • 则我们需要求出一个包含尽可能多的点的正方形。
  • 枚举正方形的右边界,用双指针维护左边界,线段树维护其中包含点数最多的区间即可。
  • 时间复杂度 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值