P2814 家谱 题解
一、理解与感悟
1、因为并查集需要编号,如果只给串的话,需要一个和数字的对应关系,用保存这个关系。
2、最后还要输出祖先的姓名,就是一个根据数字获取名字的映射关系,用来保存这个关系。
二、完整代码
#include <bits/stdc++.h>
using namespace std;
string s, name;
unordered_map<string, int> _map; //人员与编号的对应关系
unordered_map<int, string> _map2;//编号与人名的对应关系
int cnt, parentId, childId;
const int N = 200010;
int fa[N]; //并查集数组
//要深入理解这个递归并压缩的过程
int find(int x) {
if (fa[x] != x) fa[x] = find(fa[x]);
return fa[x];
}
//合并并查集
void join(int a, int b) {
int x = find(a), y = find(b);
if (x != y) fa[x] = y;
}
int main() {
//初始化并查集
for (int i = 1; i <= N; i++) fa[i] = i;
//不停的输入字符串
while (cin >> s) {
//结束标识
if (s == "$") break;
//叫啥
name = s.substr(1);
//检查首位
if (s[0] == '#') {//父亲
if (!_map[name]) {
_map[name] = ++cnt;//分配一个号码
_map2[cnt] = name; //反向记录号码对应的名字
parentId = cnt;
} else
parentId = _map[name];
} else if (s[0] == '+') {//儿子
if (!_map[name]) {
_map[name] = ++cnt;//分配一个号码
_map2[cnt] = name; //反向记录号码对应的名字
childId = cnt;
} else
childId = _map[name];
//构建并查集
join(childId, parentId);//注意顺序
} else if (s[0] == '?') {//表示要求该人的最早的祖先
childId = _map[name];
//查询并查集
cout << name << " " << _map2[find(childId)] << endl;
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
2018-08-09 Python中包(package)的调用方式
2018-08-09 NotePad++ 配置Python工作环境
2017-08-09 高速备份还原MYSQL数据库
2013-08-09 删除重复记录(Mysql,SqlServer,Sqlite)