bzoj1604 [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居
权限题贴下题面。
原题地址:http://www.lydsy.com/JudgeOnline/problem.php?id=1604
题意:
了解奶牛们的人都知道,奶牛喜欢成群结队.观察约翰的N(1≤N≤100000)只奶牛,你会发现她们已经结成了几个“群”.每只奶牛在吃草的时候有一个独一无二的位置坐标Xi,Yi(l≤Xi,Yi≤[1..10^9];Xi,Yi∈整数.当满足下列两个条件之一,两只奶牛i和j是属于同一个群的:
1.两只奶牛的曼哈顿距离不超过C(1≤C≤10^9),即lXi - xil+IYi - Yil≤C.
2.两只奶牛有共同的邻居.即,存在一只奶牛k,使i与k,j与k均同属一个群.
给出奶牛们的位置,请计算草原上有多少个牛群,以及最大的牛群里有多少奶牛
Input
第1行输入N和C,之后N行每行输入一只奶牛的坐标.
Output
仅一行,先输出牛群数,再输出最大牛群里的牛数,用空格隔开.
Sample Input
4 2
1 1
3 3
2 2
10 10
Line 1: A single line with a two space-separated integers: the
number of cow neighborhoods and the size of the largest cow
neighborhood.
Sample Output
2 3
OUTPUT DETAILS:
There are 2 neighborhoods, one formed by the first three cows and the other being the last cow. The largest neighborhood therefore has size 3.
数据范围
1≤N≤100000 ,Xi,Yi(l≤Xi,Yi≤[1..10^9],Xi,Yi∈整数
1≤C≤10^9
题解:
对于给出的曼哈顿距离的形式:|Xi - xi|+|Yi - yi|≤C.
绝对值的和,这样的形式很不好处理,这里有一个相当经典的转化方式:
曼哈顿距离 转 切比雪夫距离
对于两个点(x1,y1),(x2,y2),他们的曼哈顿距离|x1 - x2|+|y1- y2|<=c
即
-c<=x1 - x2+y1-y2<=c (1)
-c<=x1 - x2-y1+y2<=c (2)
可以转化为:
-c<=(x1+y1)-(x2+y2)<=c (1)
-c<=(x1- y1)-(x2- y2)<=c (2)
我们令X=x+y,Y=x-y。
原来的转化成了:
|X1-X2|≤C (1)
|Y1-Y2|≤C (2)
于是转化成了更好处理的切比雪夫距离。
输入时我们就进行处理,将x+y作为X坐标存储,x-y作为Y坐标存储。
因此两个点直接相连当且仅当他们的X坐标之差<=c且Y坐标之差<=c,而间接相连显然是通过直接相连,因此我们考虑将直接相连的点加入并查集。
这里给出一种算法:
把所有点按x坐标排序,依次从每个点开始朝一个方向维护一个x坐标之差<=c的队列,加入到按y坐标排序的set中,每加进一个点,在set中查找其前后驱,如果前/后驱与他的y之差<=c就把他和他前/后驱加进并查集。
这里给出一个粗浅的证明:
例如i点坐标(x,y)(转化后的),有一些x坐标小于x的点与i直接相连,我们只需把y坐标第一个小于和大于他的点与他加入并查集,由于这些点与他的x坐标之差,y坐标之差都<=c,他们都是直接相连的,只需对每个点都这样只连y坐标之差最近的两个点,就像一条链一样,即可保证所有这些点都加入了一个并查集。
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<set>
using namespace std;
const int N=100005;
int n,c,fa[N],size[N];
const int inf=1e9+10;
struct node
{
int x,y;
node(){}
node(int x,int y):x(x),y(y){}
bool friend operator<(const node &A,const node &B)
{
return A.y<B.y;
}
bool friend operator==(const node &A,const node &B)
{
return (A.x==B.x)&&(A.y==B.y);
}
}p[N];
bool cmp(const node &A,const node &B)
{
return A.x<B.x;
}
int getfa(int x)
{
if(fa[x]==x) return x;
else return fa[x]=getfa(fa[x]);
}
bool cmpy(int &A,int &B)
{
return p[A].y<p[B].y;
}
void merge(int x,int y)
{
int fx=getfa(x); int fy=getfa(y);
if(fx==fy) return;
fa[fy]=fx;
}
set<pair<int,int> > S;
int main()
{
scanf("%d%d",&n,&c);
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<=n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
p[i].x=x+y; p[i].y=x-y;
}
sort(p+1,p+n+1,cmp);
S.insert(make_pair(-inf,-inf)); S.insert(make_pair(inf,inf));
int lf=1;
S.insert(make_pair(p[1].y,1));
for(int i=2;i<=n;i++)
{
while(p[i].x-p[lf].x>c)
{S.erase(make_pair(p[lf].y,lf));lf++;}
S.insert(make_pair(p[i].y,i));
pair<int,int> pre=*--S.find(make_pair(p[i].y,i));
pair<int,int> nxt=*++S.find(make_pair(p[i].y,i));
if(pre.second!=-inf&&p[i].y-pre.first<=c) merge(i,pre.second);
if(nxt.second!=inf&&nxt.first-p[i].y<=c) merge(i,nxt.second);
}
int cnt=0; int mx=-1;
for(int i=1;i<=n;i++)
{
int fx=getfa(i);
size[fx]++; if(fx==i) cnt++;
}
for(int i=1;i<=n;i++) mx=max(mx,size[i]);
printf("%d %d\n",cnt,mx);
return 0;
}
我最开始是顺着写的,因为忽略了可能最后出现j
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<set>
using namespace std;
const int N=100005;
int n,c,fa[N],size[N];
const int inf=1e9+10;
struct node
{
int x,y;
node(){}
node(int x,int y):x(x),y(y){}
bool friend operator<(const node &A,const node &B)
{
return A.y<B.y;
}
bool friend operator==(const node &A,const node &B)
{
return (A.x==B.x)&&(A.y==B.y);
}
}p[N];
bool cmp(const node &A,const node &B)
{
return A.x<B.x;
}
int getfa(int x)
{
if(fa[x]==x) return x;
else return fa[x]=getfa(fa[x]);
}
bool cmpy(int &A,int &B)
{
return p[A].y<p[B].y;
}
void merge(int x,int y)
{
int fx=getfa(x); int fy=getfa(y);
if(fx==fy) return;
fa[fy]=fx;
}
set<pair<int,int> > S;
int main()
{
scanf("%d%d",&n,&c);
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<=n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
p[i].x=x+y; p[i].y=x-y;
}
sort(p+1,p+n+1,cmp);
S.insert(make_pair(-inf,-inf)); S.insert(make_pair(inf,inf));
int i=1,j=1;
for(i=1;i<=n;i++)
{
S.insert(make_pair(p[i].y,i));
while((j<n&&p[j+1].x-p[i].x<=c))
{
j++;
S.insert(make_pair(p[j].y,j));
pair<int,int> pre=*--S.find(make_pair(p[j].y,j));
pair<int,int> nxt=*++S.find(make_pair(p[j].y,j));
if(pre.second!=-inf&&p[j].y-pre.first<=c) merge(j,pre.second);
if(nxt.second!=inf&&nxt.first-p[j].y<=c) merge(j,nxt.second);
}
S.erase(make_pair(p[i].y,i));
}
int cnt=0; int mx=-1;
for(int i=1;i<=n;i++)
{
int fx=getfa(i);
size[fx]++; if(fx==i) cnt++;
}
for(int i=1;i<=n;i++) mx=max(mx,size[i]);
printf("%d %d\n",cnt,mx);
return 0;
}