• Hihocoder #1067 : 最近公共祖先·二


    时间限制:10000ms
    单点时限:1000ms
    内存限制:256MB

    描述

    上上回说到,小Hi和小Ho用非常拙劣——或者说粗糙的手段山寨出了一个神奇的网站,这个网站可以计算出某两个人的所有共同祖先中辈分最低的一个是谁。远在美国的他们利用了一些奇妙的技术获得了国内许多人的相关信息,并且搭建了一个小小的网站来应付来自四面八方的请求。

    但正如我们所能想象到的……这样一个简单的算法并不能支撑住非常大的访问量,所以摆在小Hi和小Ho面前的无非两种选择:

    其一是购买更为昂贵的服务器,通过提高计算机性能的方式来满足需求——但小Hi和小Ho并没有那么多的钱;其二则是改进他们的算法,通过提高计算机性能的利用率来满足需求——这个主意似乎听起来更加靠谱。

    于是为了他们第一个在线产品的顺利运作,小Hi决定对小Ho进行紧急训练——好好的修改一番他们的算法。

    而为了更好的向小Ho讲述这个问题,小Hi将这个问题抽象成了这个样子:假设现小Ho现在知道了N对父子关系——父亲和儿子的名字,并且这N对父子关系中涉及的所有人都拥有一个共同的祖先(这个祖先出现在这N对父子关系中),他需要对于小Hi的若干次提问——每次提问为两个人的名字(这两个人的名字在之前的父子关系中出现过),告诉小Hi这两个人的所有共同祖先中辈分最低的一个是谁?

    提示一:老老实实分情况讨论就不会出错的啦!

    提示二:并查集其实长得很像一棵树你们不觉得么?

    输入

    每个测试点(输入文件)有且仅有一组测试数据。

    每组测试数据的第1行为一个整数N,意义如前文所述。

    每组测试数据的第2~N+1行,每行分别描述一对父子关系,其中第i+1行为两个由大小写字母组成的字符串Father_i, Son_i,分别表示父亲的名字和儿子的名字。

    每组测试数据的第N+2行为一个整数M,表示小Hi总共询问的次数。

    每组测试数据的第N+3~N+M+2行,每行分别描述一个询问,其中第N+i+2行为两个由大小写字母组成的字符串Name1_i, Name2_i,分别表示小Hi询问中的两个名字。

    对于100%的数据,满足N<=10^5,M<=10^5, 且数据中所有涉及的人物中不存在两个名字相同的人(即姓名唯一的确定了一个人),所有询问中出现过的名字均在之前所描述的N对父子关系中出现过,第一个出现的名字所确定的人是其他所有人的公共祖先。

    输出

    对于每组测试数据,对于每个小Hi的询问,按照在输入中出现的顺序,各输出一行,表示查询的结果:他们的所有共同祖先中辈分最低的一个人的名字。

    样例输入
    4
    Adam Sam
    Sam Joey
    Sam Micheal
    Adam Kevin
    3
    Sam Sam
    Adam Sam
    Micheal Kevin
    样例输出
    Sam
    Adam
    Adam

    tarjan LCA:

    tarjan算法不只是缩点算法呀!

    DFS由深到浅处理每个子树,用并查集维护整棵子树的公共祖先。

     1 /*by SilverN*/
     2 #include<iostream>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<cstdio>
     6 #include<cmath>
     7 #include<vector>
     8 #include<map>
     9 using namespace std;
    10 const int mxn=120000;
    11 struct edge{
    12     int v,nxt;
    13 }e[mxn];
    14 int hd[mxn],mct=0;
    15 void add_edge(int u,int v){
    16     e[++mct].v=v;e[mct].nxt=hd[u];hd[u]=mct;
    17     return;
    18 }
    19 //
    20 vector<int>query[mxn];
    21 map<string,int>id;
    22 int idcnt=0;
    23 char s[mxn][300];
    24 int ans[mxn];
    25 char ql[mxn][300],qr[mxn][300];
    26 //
    27 int n,m;
    28 //
    29 int fa[mxn];
    30 void init(){for(int i=1;i<=n;i++)fa[i]=i;return;}
    31 int find(int x){
    32     if(fa[x]==x)return x;
    33     return fa[x]=find(fa[x]);
    34 }
    35 //
    36 void DFS(int u,int ff){
    37     fa[u]=u;
    38     int i,j;
    39     for(i=hd[u];i;i=e[i].nxt){
    40         DFS(e[i].v,u);
    41     }
    42     for(i=0;i<query[u].size();++i){
    43         int v=query[u][i];
    44         int tmp;
    45         if(u==id[ql[v]])tmp=id[qr[v]];
    46         else tmp=id[ql[v]];
    47         if(!fa[tmp])continue;
    48         ans[v]=find(tmp);
    49     }
    50     fa[u]=find(fa[ff]);
    51 }
    52 int main(){
    53     scanf("%d",&n);
    54     int i,j;
    55     char s1[300],s2[300];
    56     for(i=1;i<=n;i++){
    57         scanf("%s%s",s1,s2);
    58         if(!id[s1]){
    59             id[s1]=++idcnt;
    60             memcpy(s[idcnt],s1,sizeof s1);
    61         }
    62         if(!id[s2]){
    63             id[s2]=++idcnt;
    64             memcpy(s[idcnt],s2,sizeof s2);
    65         }
    66         add_edge(id[s1],id[s2]);
    67     }
    68     scanf("%d",&m);
    69     for(i=1;i<=m;i++){
    70         scanf("%s%s",ql[i],qr[i]);
    71         query[id[ql[i]]].push_back(i);
    72         query[id[qr[i]]].push_back(i);
    73     }
    74     memset(fa,0,sizeof fa);
    75     DFS(1,0);
    76     for(i=1;i<=m;i++){
    77         printf("%s
    ",s[ans[i]]);
    78     }
    79     return 0;
    80 }
  • 相关阅读:
    linux使用windows中编辑的文件,格式问题
    模拟退火算法c++
    progress第三方框架和二维码第三方框架的选择
    iOS 初始化项目内容
    github上使用SSH和gitignore
    wordpress 如何设置自定义的首页
    wordpress 删除底部"自豪地采用 WordPress"
    masonry注意事项
    iOS修改工程名
    iOS版本更新在APP中直接访问AppStore
  • 原文地址:https://www.cnblogs.com/SilverNebula/p/5947794.html
Copyright © 2020-2023  润新知