题目
有两种操作。
0是 设置两人同阵营
1是 查询两人是否同阵营
输入
每个测试点(输入文件)有且仅有一组测试数据。
每组测试数据的第1行为一个整数N,表示总共进行的操作次数。
每组测试数据的第2~N+1行,每行分别描述一次操作,其中第i+1行为一个整数op_i和两个由大小写字母组成的字符串Name1_i, Name2_i,其中op_i只可能为0或1,当op_i=0时,表示判定Name1_i和Name2_i是同一阵营的,当op_i=1时,表示希望知道Name1_i和Name2_i是否为同一阵营的。
对于100%的数据,满足N<=10^5, 且数据中所有涉及的人物中不存在两个名字相同的人(即姓名唯一的确定了一个人),对于所有的i,满足Name1_i和Name2_i是不同的两个人。
输出
对于每组测试数据,对于黑叔叔每次op_i=1的操作,输出一行,表示查询的结果:如果根据已知信息(即这次操作之前的所有op_i=0的操作),可以判定询问中的两个人是同一阵营的,则输出yes,否则输出no。
思路
简单的并查集工作。
集合的定义方法。
我们可以把一个集合定义为一种链的形式。
如果a和b是同一集合,则有a和b的end都相同。
若a单独是一个集合的时候,那么end就等于a。
下面我直接把end称作集合的名字。
集合的并
比如有a所在的集合end_a和b所在的集合end_b,我们要把a所在的集合和b所在的集合相并,那么直接将end_a的next指向end_b,这样a所在的集合的end就变成了end_b,a和b也就在同一个集合里了。
集合的查
上面说过了,如果a和b是同一集合,则有a和b的end都相同。
代码
这里我是虽然直接用的一个 map<string,sting>,但是这样做的使得我这代码效率很低。应该把string转化为数字id再用这个id做并查集的。这里我懒了。
#include<cstdio>
#include<iostream>
#include<string>
#include<map>
using namespace std;
map<string,string> fa;
int N;
string find_fa(string b)
{
if(fa.count(b)) return fa[b]=find_fa(fa[b]);
return b;
}
void set_represent(string a,string b)
{
string ra=find_fa(a),rb=find_fa(b);
if(ra!=rb)
fa[find_fa(a)]=find_fa(b);
}
void find_represent(string a,string b)
{
if(find_fa(a)==find_fa(b)) cout<<"yes"<<endl;
else cout<<"no"<<endl;
}
int main()
{
scanf("%d",&N);
int m;
string a,b;
while(N--)
{
scanf("%d",&m);
cin>>a>>b;
if(m) find_represent(a,b);
else set_represent(a,b);
}
return 0;
}