第一维直接遍历 第二维用线段树维护每个最左端可以得到的贡献
在线段树上每次删除一个点会影响到 X X-R X-2*R 3个值 最多操作1e5次 复杂度 6*n*logn(删了还要加回来
#include<bits/stdc++.h> using namespace std; const int MAXN = 300005; int num[MAXN]; int number[MAXN]; struct Seg_Tre { int l, r; int w; } tree[MAXN << 2]; inline void push_up(int x) { tree[x].w = max(tree[x << 1].w, tree[(x << 1) | 1].w); } inline void build(int x, int ll, int rr) { tree[x].l = ll, tree[x].r = rr; if (tree[x].l == tree[x].r) { tree[x].w = number[ll]; return; } int m = (ll + rr) >> 1; build(x << 1, ll, m); build((x << 1 | 1), m + 1, rr); push_up(x); } inline void change_point(int x, int aim, int add) { if (tree[x].l == tree[x].r) { tree[x].w += add; return; } int m = (tree[x].l + tree[x].r) >> 1; if (aim <= m) { change_point(x << 1, aim, add); } else { change_point((x << 1) | 1, aim, add); } push_up(x); } inline int ask_interval(int x, int ll, int rr) { if (tree[x].l > rr || tree[x].r < ll) return -1; if (tree[x].l >= ll && tree[x].r <= rr) { return tree[x].w; } int now = 0; int m = (tree[x].l + tree[x].r) >> 1; if (ll <= m) { now = max(now, ask_interval(x << 1, ll, m)); } if (rr > m) { now = max(now, ask_interval((x << 1) | 1, m + 1, rr)); } return now; } vector<int> G[MAXN]; int main() { int n, r; int x, y; scanf("%d %d", &n, &r); for (int i = 1; i <= n; i++) { scanf("%d %d", &x, &y); G[x].push_back(y); num[y]++; } for (int i = 0; i <= 100000; i++) { for (int j = 0; j <= 2; j++) { if (i + j * r <= 100000) { number[i] += num[i + j * r]; } } } build(1, 0, 100000); int ansnow = 0; for (int i = 0; i <= 100000; i++) { int now = 0; for (int j = 0; j <= 2; j++) { int u = i + j * r; if (u > 100000) break; for (int v : G[u]) { now++; for (int k = 0; k <= 2; k++) if (v - k * r >= 0) change_point(1, v - k * r, -1); } } ansnow = max(ansnow, now + ask_interval(1,0,100000)); for (int j = 0; j <= 2; j++) { int u = i + j * r; if (u > 100000) break; for (int v : G[u]) { now++; for (int k = 0; k <= 2; k++) if (v - k * r >= 0) change_point(1, v - k * r, 1); } } } printf("%d ", ansnow); return 0; }