题解 P2906 【[USACO08OPEN]牛的街区Cow Neighborhoods】
Description
题目链接:Luogu 2906
了解奶牛们的人都知道,奶牛喜欢成群结队。观察约翰的
- 两只奶牛的曼哈顿距离不超过
C ,即|X_i-X_j|+|Y_i-Y_j|\le C 。 - 两只奶牛有共同的邻居。即存在一只奶牛
k ,使i 与k 、j 与k 均同属一个群。
请计算有多少个牛群,以及最大的牛群里有多少奶牛。
数据范围:
Solution
首先我们有一个转化:曼哈顿距离转切比雪夫距离。将一个点的坐标
设第
- 两只奶牛的切比雪夫距离不超过
C ,即\max(\vert x_1-x_2\vert,\vert y_1-y_2\vert)\le C 。
由于有
我们用
最后我们证明其他的点不需要和
对于大于等于
时间复杂度:
Code
#include <cstdio>
#include <algorithm>
#include <set>
typedef std::pair<long long,int> pli;
typedef std::pair<long long,long long> pll;
#define mk std::make_pair
const int N=1e5+5;
int n,C,fa[N],cnt[N];
pll a[N];
std::set<pli> s;
int find(int x) {
return fa[x]==x?x:fa[x]=find(fa[x]);
}
void merge(int x,int y) {
fa[find(x)]=find(y);
}
int main() {
scanf("%d%d",&n,&C);
for(int i=1;i<=n;++i) {
int X,Y;
scanf("%d%d",&X,&Y);
a[i]=mk(X+Y,X-Y),fa[i]=i;
}
std::sort(a+1,a+n+1);
s.insert(mk(-1LL<<60,0)),s.insert(mk(1LL<<60,0));
s.insert(mk(a[1].second,1));
for(int l=1,i=2;i<=n;++i) {
while(a[i].first-a[l].first>C) s.erase(mk(a[l].second,l)),++l;
std::set<pli>::iterator it=s.lower_bound(mk(a[i].second,0));
if(it->first-a[i].second<=C) merge(i,it->second);
--it;
if(a[i].second-it->first<=C) merge(i,it->second);
s.insert(mk(a[i].second,i));
}
int ans=0,mx=0;
for(int i=1;i<=n;++i) ans+=(find(i)==i),mx=std::max(mx,++cnt[find(i)]);
printf("%d %d\n",ans,mx);
return 0;
}