其他分享
首页 > 其他分享> > P2814 家谱 题解

P2814 家谱 题解

作者:互联网

题目传送门

一、理解与感悟

1、因为并查集需要编号,如果只给串的话,需要一个和数字的对应关系,用\(\_map\)保存这个关系。
2、最后还要输出祖先的姓名,就是一个根据数字获取名字的映射关系,用\(\_map2\)来保存这个关系。

二、完整代码

#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;
}

标签:map,cnt,name,fa,int,题解,查集,P2814,家谱
来源: https://www.cnblogs.com/littlehb/p/15118885.html