题解
题目描述
链接:https://ac.nowcoder.com/acm/contest/6241/F
解题思路
给你n个点,判断能否由一个点到达另一个点,由题可知,一个点能到这个点所在行和列上的任意一个点上,所以对于一个点,我们把他所在行和所在列的所有点都放在一个集合里,或者说对于每一行,这一行上所有点的标号属于同一个集合,对于每一列,这一列上所有点的标号属于同一个集合。注意这不是行集合或者列集合,这是点的标号集合,所以对于一个点是因为列相等而处于这个集合中的也就会有可能有另一个点是因为行相等而处于这个集合中。这里我们采用并查集的结构。
1.用r[]数组记录每一行的root点的标号,用c[]数组记录每一列的root点的标号,初始都为0。
2.对于每一个点,我们看他的行a,是否有root点,没有,这一个点设为改行的root点,有将这个点与root点合并在一个集合里。对于列同理。
3.对于每一次查询,看这两个点是否在一个集合中,在yes,不在no。
ps:输入最好用scanf,不知道为什么,用快读这种方法会超时。(可能是因为回车和空格太多的原因)
代码如下
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int fa[1000010];
int c[100001];//记录每一列的root点的标号
int r[100001];//记录每一行的root点的标号
inline int read()//快读,并未使用。
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
int findfa(int x)//找祖宗和路径压缩
{
return fa[x]==x ? x : fa[x]=findfa(fa[x]);
}
void mergefa(int i,int j)//合并并查集
{
int a=findfa(i),b=findfa(j);
if(a!=b)
fa[b]=a;
}
int main()
{
int n,q;
scanf("%d%d",&n,&q);
for(int i=0;i<=n;i++)
fa[i]=i;
for(int i=1;i<=n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
if(!r[a])
r[a]=i;
else
mergefa(r[a],i);
if(!c[b])
c[b]=i;
else
mergefa(c[b],i);
}
while(q--)
{
int i,j;
scanf("%d%d",&i,&j);
if(findfa(i)==findfa(j))
printf("YES\n");
else
printf("NO\n");
}
return 0;
}