#include using namespace std; string s, name; unordered_map _map; //人员与编号的对应关系 unordered_map _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; }