zoukankan      html  css  js  c++  java
  • hihoCoder #1067 最近公共祖先·二

    #1067 : 最近公共祖先·二

    Time Limit:10000ms
    Case Time Limit:1000ms
    Memory Limit: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的询问,按照在输入中出现的顺序,各输出一行,表示查询的结果:他们的所有共同祖先中辈分最低的一个人的名字。

    Sample Input
    4
    Adam Sam
    Sam Joey
    Sam Micheal
    Adam Kevin
    3
    Sam Sam
    Adam Sam
    Micheal Kevin
    Sample Output
    Sam
    Adam
    Adam

    解题:LCA

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cmath>
     5 #include <algorithm>
     6 #include <climits>
     7 #include <vector>
     8 #include <queue>
     9 #include <cstdlib>
    10 #include <string>
    11 #include <set>
    12 #include <map>
    13 #include <stack>
    14 #define LL long long
    15 #define INF 0x3f3f3f3f
    16 #define pii pair<int,int>
    17 using namespace std;
    18 const int maxn = 200010;
    19 struct arc{
    20     int to,next;
    21     arc(int x = 0,int y = -1){
    22         to = x;
    23         next = y;
    24     }
    25 };
    26 arc e[1000000];
    27 int head[maxn],uf[maxn],fa[maxn],ans[maxn];
    28 int tot,cnt,n,m;
    29 bool vis[maxn];
    30 vector< pii >query[maxn];
    31 void add(int u,int v){
    32     e[tot] = arc(v,head[u]);
    33     head[u] = tot++;
    34 }
    35 int Find(int x){
    36     if(x != uf[x]) uf[x] = Find(uf[x]);
    37     return uf[x];
    38 }
    39 void tarjan(int u){
    40     fa[u] = u;
    41     for(int i = head[u]; ~i; i = e[i].next){
    42         //if(vis[e[i].to]) continue;
    43         tarjan(e[i].to);
    44         int x = Find(e[i].to);
    45         uf[x] = uf[Find(u)];
    46         fa[Find(u)] = u;
    47     }
    48     vis[u] = true;
    49     for(int i = query[u].size()-1; i >= 0; --i)
    50         if(vis[query[u][i].first]) ans[query[u][i].second] = fa[Find(query[u][i].first)];
    51 }
    52 void init(){
    53     for(int i = 0; i < maxn; ++i){
    54         head[i] = -1;
    55         vis[i] = false;
    56         query[i].clear();
    57         uf[i] = i;
    58     }
    59     tot = 0;
    60     cnt = 1;
    61 }
    62 map<string,int>mp;
    63 string name[maxn],a,b;
    64 int main(){
    65     int u,v;
    66     while(~scanf("%d",&n)){
    67         init();
    68         mp.clear();
    69         for(int i = 0; i < n; ++i){
    70             cin>>a>>b;
    71             if(mp[a]) u = mp[a];
    72             else{
    73                 u = mp[a] = cnt;
    74                 name[cnt++] = a;
    75             }
    76             if(mp[b]) v = mp[b];
    77             else{
    78                 v = mp[b] = cnt;
    79                 name[cnt++] = b;
    80             }
    81             add(u,v);
    82         }
    83         scanf("%d",&m);
    84         for(int i = 0; i < m; ++i){
    85             cin>>a>>b;
    86             query[mp[a]].push_back(make_pair(mp[b],i));
    87             query[mp[b]].push_back(make_pair(mp[a],i));
    88         }
    89         for(int i = 1; i < cnt; ++i){
    90             if(!vis[i]) tarjan(i);
    91         }
    92         //tarjan(1);
    93         for(int i = 0; i < m; ++i)
    94             cout<<name[ans[i]]<<endl;
    95     }
    96     return 0;
    97 }
    View Code
  • 相关阅读:
    Optional类的基本使用(没怎么看)
    443. String Compression字符串压缩
    520. Detect Capital判断单词有效性
    521. Longest Uncommon Subsequence I 最长不同子数组
    459. Repeated Substring Pattern 判断数组是否由重复单元构成
    686. Repeated String Match 字符串重复后的子字符串查找
    696. Count Binary Substrings统计配对的01个数
    58. Length of Last Word最后一个单词的长度
    680. Valid Palindrome II 对称字符串-可删字母版本
    125. Valid Palindrome判断有效的有符号的回文串
  • 原文地址:https://www.cnblogs.com/crackpotisback/p/4134937.html
Copyright © 2011-2022 走看看