前置技能:曼哈顿距离转切比雪夫距离
曼哈顿距离:已知两点$A(x_{1},y_{1})$,$B(x_{2},y_{2})$,则其曼哈顿距离为$|x_{2}-x_{1}|+|y_{2}-y_{1}|$
切比雪夫距离:已知两点$A(x_{1},y_{1})$,$B(x_{2},y_{2})$,则其切比雪夫距离为$max(|x_{2}-x_{1}|,|y_{2}-y_{1}|)$
二者的转化:
已知两点$A(x_{1},y_{1})$,$B(x_{2},y_{2})$,设$A^{'}(x_{1}+y_{1},x_{1}-y_{1})$,$B^{'}(x_{2}+y_{2},x_{2}-y_{2})$
则$AB$两点的曼哈顿距离与$A^{'}B^{'}$之间的切比雪夫距离相等
证明显然
因此我们对每个点$P_{i}(x_{i},y_{i})$,构造一个新的点$P_{i}^{'}(x_{i}+y_{i},x_{i}-y_{i})$,这样我们只研究新点之间的切比雪夫距离即可
为什么我们要这样做?
这样的话我们就可以分别处理$x$和$y$了
我们把所有的新点按照$x$进行排序,然后维护一个$set$里存原先的$y$
从小向大枚举$x$,每枚举到一个$x$就先把之前x不合法的部分从set里删除,再在set里面查这个$y$的前驱后继,如果合法就连边(注意只想前驱后继连边即可,用并查集维护),再把y插入set中即可
这样做的合理性在于,显然连的所有边都是合法的,而且根据传递性只需相邻的连边就能维护一个完整的集合了
这样代码就很好写了
#include <cstdio> #include <cmath> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #include <queue> #include <stack> #include <set> #define ll long long using namespace std; struct node { ll x,y; friend bool operator < (node a,node b) { return a.x==b.x?a.y<b.y:a.x<b.x; } }p[100005]; int n,C; int f[100005],siz[100005]; int findf(int x) { return x==f[x]?x:f[x]=findf(f[x]); } struct Info { ll y; int num; friend bool operator < (Info a,Info b) { return a.y==b.y?a.num<b.num:a.y<b.y; } }; set <Info> S; template <typename T>inline void read(T &x) { T f=1,c=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();} x=c*f; } void merge(int x,int y) { int f1=findf(x),f2=findf(y); if(f1!=f2)f[f2]=f1,siz[f1]+=siz[f2]; } int main() { read(n),read(C); for(int i=1;i<=n;i++) { ll rx,ry; read(rx),read(ry); p[i].x=rx+ry,p[i].y=rx-ry; f[i]=i,siz[i]=1; } sort(p+1,p+n+1); int las=1; S.insert((Info){-0x3f3f3f3f3f3f3f3fll,0}),S.insert((Info){0x3f3f3f3f3f3f3f3fll,0}); S.insert((Info){p[1].y,1}); for(int i=2;i<=n;i++) { while(p[i].x-p[las].x>C&&las<i)S.erase((Info){p[las].y,las}),las++; set <Info>::iterator it1; it1=S.lower_bound((Info){p[i].y,0}); if(it1!=S.end()&&abs(p[i].y-(*it1).y)<=C)merge(i,(*it1).num); it1--; if(it1!=S.end()&&abs(p[i].y-(*it1).y)<=C)merge(i,(*it1).num); S.insert((Info){p[i].y,i}); } int cnt=0,ans=0; for(int i=1;i<=n;i++)if(f[i]==i)cnt++,ans=max(ans,siz[i]); printf("%d %d ",cnt,ans); return 0; }