hiho刷题日记——第十四天无间道之并查集

题目

有两种操作。
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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值