All in the Family_upc_模拟 or lca + 并查集

简介: The scientists working at the Family Genetics Institute are tracing the spread of a hereditary disease through family trees. They have started by listing the family members that have the disease,

The scientists working at the Family Genetics Institute are tracing the spread of a hereditary disease through family trees. They have started by listing the family members that have the disease, and the parent who passed the disease on to each child (we will assume that each child gets the disease from only one parent). However, the scientists are confused about the names of different family relationships. Parents, grandparents, and siblings they have a handle on. But a relationship like “third cousin, twice removed” has been hard for them to wrap their heads around. After much discussion they came up with some definitions that cleared things up.


Suppose we have two people conveniently named A and B and their closest common ancestor is named C (what are the odds!). We say that A is m generations removed from C  if there are m direct descendants from C ending with A. Thus if A is the daughter of C she is 1 generation removed; if she is the granddaughter of C she is 2 generations removed, and so on. Any person is 0 generations removed from themselves.


Now let A be m generations removed from C and B be n generations removed from C where m≤n. We can determine the relationship between A and B using the following rules:

1.if m=0 then B is the child of A if n=1 or the greatn−2 grandchild of A if n>1.

2.if 0<m=n then A and B are siblings if n=1 or (n−1)-th cousins if n>1.

3.if 0<m<n then A and B are (m−1)-th cousins (n−m) times removed.

Notice that if m=1 and n=2 we get the interestingly named “0th cousins, 1 time removed” for the relationships we typically describe as “aunt/uncle” or “niece/nephew”.


Figure 1 below shows some examples for two new people named (what else) D and E.

微信图片_20220609152013.png


The scientists have given you the description of a family tree and pairs of people in the tree and have asked you to determine the relationships between members of each pair.


输入


Input begins with a line containing two positive integers t p (t≤100,p≤1000) specifying the number of tree descriptions (described below) and the number of query pairs. Following these are t lines, each with one tree description. Each tree description will be of the form s0 d s1 s2…sd indicating that person s0 has d children named s1 through sd. All names are unique and contain only alphabetic characters. Tree descriptions may be given in any order (i.e., the root of the entire tree may not necessarily be in the very first tree description). No name will appear more than once as s0 in the tree descriptions. All the tree descriptions will combine to form exactly one tree, and the tree will have at least 2 nodes and at most 100 nodes.

Following this are p lines of the form si sj where si≠sj and both names are guaranteed to be in the tree.

输出


Output the relationship for each pair of people, one per line, using the formats shown in Figure 1. Always output si’s name first for each pair except when sj is the direct descendant of si (as in the first example in Figure 1). For the n-th ordinal number output nth except for n=1,2,3,21,22,23,31,32,33,… in which case you should output 1st, 2nd, 3rd, 21st, 22nd, 23rd, 31st, 32nd, 33rd, etc. Also be sure to use times for all times removed except one, where you should use the word time.


样例输入 Copy


【样例1】

4 5
Horatio 1 Irene
Chris 2 Gina Horatio
Alice 3 Dan Emily Frank
Bob 2 Alice Chris
Irene Bob
Dan Frank
Chris Emily
Alice Chris
Dan Irene


【样例2】

4 6
A 4 B C D E
H 3 I J K
C 2 F G
D 1 H
G C
H A
F G
F H
F K
B K


样例输出 Copy


【样例1】

Irene is the great grandchild of Bob
Dan and Frank are siblings
Chris and Emily are 0th cousins, 1 time removed
Alice and Chris are siblings
Dan and Irene are 1st cousins, 1 time removed


【样例2】

G is the child of C
H is the grandchild of A
F and G are siblings
F and H are 1st cousins
F and K are 1st cousins, 1 time removed
B and K are 0th cousins, 2 times removed


题意:首先有T行,每行包含父亲节点的名字以及孩子的数量,紧跟其后的是孩子的名字

然后查询有P行,每行包含两个名字,输出两个人之间的关系


首先从题面中我们可以读出输入的T行中有明显的父子关系,然后我们就可以通过建图来解决,在求解两个人之间的关系的时候,我们有必要首先确定根节点(不能使随便的节点就当作根节点,会影响答案),因为这个是可以家族的关系树,所以说跟节点只有一个,这个时候就可以将字符串转换为数字(map标记一下就好),然后用并查集求解根节点-> i == find(i)


建立了根节点之后,我们可以通过LCA来求出两个人最近公共祖先的深度,然后通过要询问的两个点深度和LCA之间的深度关系来确定题面里说的n,m的大小(作差),然后在得到n,m之后,就可以输出两个人之间的关系(输出不得不说很烦人)

还有许要注意的是:11th,12th, 13th(有3%左右的数据)

1st,2nd,3rd,21st,22nd,23rd…


数据范围比较小,也可以暴力模拟,附上 大佬链接

int t, p;
int root;
int head[maxn];
int fat[maxn];
map<int, string> list;
struct node
{
    int u;
    int v;
    int next;
} e[maxn];
int dep[maxn];/// save the depth of every node
int fa[maxn][30];
int lg[maxn];
int cnt = 0;
void init()
{
    for(int i = 1; i <= 100000; i++) head[i] = -1;
}
void add(int u, int v)
{
    e[cnt].u = u;
    e[cnt].v = v;
    e[cnt].next = head[u];
    head[u] = cnt ++;
}
void dfs(int cur, int rt)
{
    fa[cur][0] = rt, dep[cur] = dep[rt] + 1; /// the depth of the current node changed
    for(int i = 1; i <= lg[dep[cur]]; i++)
    {
        fa[cur][i] = fa[fa[cur][i - 1]][i - 1];
    }
    for(int i = head[cur]; ~i; i = e[i].next) /// visit all linked nodes
    {
        if(e[i].v != rt) dfs(e[i].v, cur);
    }
}
void cal()
{
    for(int i = 1; i <= 100000; i++)
    {
        lg[i] = lg[i - 1] + (1 << lg[i - 1] == i); /// 2 ^ lg[i-1] == i true + 1
    }
}
int lca(int x, int y)
{
    if(dep[x] < dep[y]) swap(x, y);
    while(dep[x] > dep[y]) x = fa[x][lg[dep[x] - dep[y]] - 1];
    if(x == y) return y;
    /// big -> small
    for(int k = lg[dep[x]] - 1; k >= 0; k --)
    {
        if(fa[x][k] != fa[y][k])
        {
            x = fa[x][k];
            y = fa[y][k];
        }
    }
    return fa[x][0];
}
void fainit()
{
    for(int i = 1; i <= 100000; i++) fat[i] = i;
}
int find(int x)
{
    if(x == fat[x]) return x;
    else return fat[x] = find(fat[x]);
}
map<string, int> mp;
map<int, string>mp2;
string fun(int x)
{
    if(x == 11 || x == 12 || x == 13) return "th";
    else
    {
        if(list[x % 10] != "") return list[x % 10];
        else return "th";
    }
}
string fun2(int x)
{
    if(x < 2) return " time";
    else return " times";
}
int main()
{
    //freopen("wa.out", "w", stdout);
    list[1] = "st", list[2] = "nd", list[3] = "rd";
    cin >> t >> p;
    cal(), init(), fainit();
    int tot = 0;
    for(int i = 1; i <= t; i++)
    {
        string name;
        cin >> name;
        int u, v;
        if(mp[name]) u = mp[name];
        else mp[name] = ++ tot, u = mp[name], mp2[tot] = name;
        int x;
        cin >> x;
        for(int j = 1; j <= x; j++)
        {
            string Son;
            cin >> Son;
            if(!mp[Son]) mp[Son] = ++ tot, mp2[tot] = Son;
            v = mp[Son];
            fat[v] = u;
            add(u, v);
            add(v, u);
        }
    }
    for(int i = 1; i <= tot; i++)
    {
        if(i == find(i))
        {
            root = i;
            break;
        }
    }
    dfs(root, 0);
    for(int i = 1; i <= p; i++)
    {
        string a, b;
        cin >> a >> b;
        int u = mp[a], v = mp[b];
        int lc = lca(u, v);
        int depu = dep[u], depv = dep[v];
        int deplc = dep[lc];
        int dfu = depu - deplc, dfv = depv - deplc;
        if(dfu == 0 || dfv == 0)
        {
            if(dfu == 0)
            {
                if(dfv == 1) cout << b << " is the child of " << a << endl;
                else
                {
                    cout << b << " is the ";
                    int cnt = dfv - 2;
                    while(cnt --) cout << "great ";
                    cout << "grandchild of " << a << endl;
                }
            }
            else if(dfv == 0)
            {
                if(dfu == 1) cout << a << " is the child of " << b << endl;
                else
                {
                    cout << a << " is the ";
                    int cnt = dfu - 2;
                    while(cnt --) cout << "great ";
                    cout << "grandchild of " << b << endl;
                }
            }
        }
        else if(dfu == dfv)
        {
            if(dfu == 1) cout << a << " and " << b << " are siblings" << endl;
            else
            {
                cout << a << " and " << b << " are " << dfu - 1 << fun(dfu - 1);
                cout << " cousins" << endl;
            }
        }
        else
        {
            if(dfu < dfv)
            {
                cout << a << " and " << b << " are " << dfu - 1 << fun(dfu - 1) << " cousins, ";
                cout << dfv - dfu  << fun2(dfv - dfu) << " removed" << endl;
            }
            else
            {
                swap(dfu, dfv);
                cout << a << " and " << b << " are " << dfu - 1 << fun(dfu - 1) << " cousins, ";
                cout << dfv - dfu  << fun2(dfv - dfu) << " removed" << endl;
            }
        }
    }
    return 0;
}


目录
相关文章
light oj 1159 - Batman LCS
学过简单动态规划的人应该对最长公共子序列的问题很熟悉了,这道题只不过多加了一条字符串变成三条了,还记得,只要把状态变成三维的即可。
32 0
Light oj 1112 - Curious Robin Hood(树状数组)
有n个数,有m组操作,1 i表示将第i个数先输出,然后置0, 2 i v 表示给第i个数加上v, 3 i j 表示求i 到 j 的和,注意,这里数组是从0开始的,而我们构造的树状数组是从1 开始的,使用在程序中要进行一定的处理。
41 0
|
机器学习/深度学习
light oj 1005 - Rooks(组合数学)
组合数学解法 现在n行中选出m行,C(n,m),再在n列中选出m列随便放A(n,m),答案为C(n,m)*A(n,m)。
37 0
|
人工智能
POJ 2299 Ultra-QuickSort(树状数组+离散化+求逆序数)
POJ 2299 Ultra-QuickSort(树状数组+离散化+求逆序数)
初学算法之二叉树---求树的高度 pta
初学算法之二叉树---求树的高度 pta
|
人工智能 vr&ar
SPOJ - COT Count on a tree(主席树 LCA)
SPOJ - COT Count on a tree(主席树 LCA)
93 0
UPC Graph (最小生成树 || 并查集+二分)
UPC Graph (最小生成树 || 并查集+二分)
92 0
CF191C——Fools and Roads(树上边差分+LCA)
CF191C——Fools and Roads(树上边差分+LCA)
125 0
|
人工智能
【待补】UPC No Need(二分+bitset || 背包dp)
【待补】UPC No Need(二分+bitset || 背包dp)
57 0
|
定位技术
UPC——帕琪的药园(dfs或并查集)
UPC——帕琪的药园(dfs或并查集)
78 0