1 条题解
-
0
自动搬运
来自洛谷,原作者为

Siyuan
Dream OIer.搬运于
2025-08-24 21:43:18,当前版本为作者最后更新于2019-02-08 11:25:18,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
Description
题目链接:Luogu 2906
了解奶牛们的人都知道,奶牛喜欢成群结队。观察约翰的 只奶牛,你会发现她们已经结成了几个“群”。每只奶牛在吃草的时候有一个独一无二的位置坐标 。当满足下列两个条件之一,两只奶牛 和 是属于同一个群的:
- 两只奶牛的曼哈顿距离不超过 ,即 。
- 两只奶牛有共同的邻居。即存在一只奶牛 ,使 与 、 与 均同属一个群。
请计算有多少个牛群,以及最大的牛群里有多少奶牛。
数据范围:,,
Solution
首先我们有一个转化:曼哈顿距离转切比雪夫距离。将一个点的坐标 转化成 ,设新点的坐标为 ,那么原来的曼哈顿距离 就等于现在的切比雪夫距离 。可以通过分类讨论或几何法简单证明成立。
设第 个点的新坐标为 ,记为 。那么第 个限制会变为:
- 两只奶牛的切比雪夫距离不超过 ,即 。
由于有 ,我们可以将 以 为第一个关键字, 为第二关键字,从小到大排序。对于同一群的奶牛我们用并查集合并。
我们用 维护 (每个点)的值,我们每次在插入第 个点时,先把 中所有满足 的点都删除,然后用 \text{lower_bound} 找到第一个大于等于 的点,如果满足约束条件就将这两个点合并起来。再找到最后一个小于 的点,进行相同合并操作。
最后我们证明其他的点不需要和 合并。
对于大于等于 的点 满足约束条件 ,那么 ,那么在处理 或 时一定会把 合并进来(这取决于 和 的大小),所以不必合并了。对于小于的部分证明同理。
时间复杂度:
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; }
- 1
信息
- ID
- 1971
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者