传送门
考虑将曼哈顿距离转换成切比雪夫距离,这样问题就变成了max(∣x1−x2∣,∣y1−y2∣)≤dmax(|x_1-x_2|,|y_1-y_2|)\le dmax(∣x1−x2∣,∣y1−y2∣)≤d,这个式子就很好看了,我们首先按照(x,y)(x,y)(x,y)排序,让后我们双指针控制∣xr−xl∣<=d|x_r-x_l|<=d∣xr−xl∣<=d,用multisetmultisetmultiset维护[l,r][l,r][l,r]内的yyy坐标,一开始比较暴力的想法就是找到[yr−d,yr+d][y_r-d,y_r+d][yr−d,yr+d]区间内的数,让后用并查集维护,但是这样显然是可以卡成O(n2)O(n^2)O(n2)的,仔细想一下,有必要遍历所有点吗?并没有,假设我们二分找到了≥yr−d\ge y_r-d≥yr−d的第一个位置pospospos,那么不难发现[pos,pos+d][pos,pos+d][pos,pos+d]对应的数都已经合并到一个集合中了,并没有必要去遍历,所以我们只需要找yr−d,yr+1y_r-d,y_r+1yr−d,yr+1对应在multisetmultisetmultiset里面的位置即可。
复杂度O(nlogn)O(nlogn)O(nlogn)
#include<bits/stdc++.h>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define Mid (tr[u].l+tr[u].r>>1)
#define pb push_back
using namespace std;const int N=1000010,INF=0x3f3f3f3f,mod=1e9+7;
typedef long long LL;
typedef pair<int,int> PII;int n,d;
int p[N],se[N];
struct Point {int x,y;bool operator < (const Point &W) const {if(x!=W.x) return x<W.x;else return y<W.y;}
}a[N];int find(int x) {return x==p[x]? x:p[x]=find(p[x]);
}void solve() {multiset<PII>s;scanf("%d%d",&n,&d);for(int i=1;i<=n;i++) {int x,y;scanf("%d%d",&x,&y);p[i]=i;a[i].x=x+y; a[i].y=x-y;}sort(a+1,a+1+n);for(int l=1,r=1;r<=n;r++) {s.insert({a[r].y,r});while(a[r].x-a[l].x>d) {s.erase(s.find({a[l].y,l}));l++;}int y=a[r].y;auto it=s.lower_bound({y-d,0});if(it!=s.end()) {PII u=*it;if(u.X<=y+d) {p[find(r)]=find(u.Y);it=s.lower_bound({y+1,0});if(it!=s.end()) {u=*it;if(u.X<=y+d) {p[find(r)]=find(u.Y);}}}}}int ans,mx;ans=0; mx=0;for(int i=1;i<=n;i++) {if(se[find(i)]==0) ans++;se[find(i)]++;mx=max(mx,se[find(i)]);}printf("%d %d\n",ans,mx);
}int main() {int _=1;while(_--) {solve();}return 0;
}
/**/