zoukankan      html  css  js  c++  java
  • 【HIHOCODER 1067】最近公共祖先·二(LCA)

    描述


    上上回说到,小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<=105,M<=105, 且数据中所有涉及的人物中不存在两个名字相同的人(即姓名唯一的确定了一个人),所有询问中出现过的名字均在之前所描述的N对父子关系中出现过,第一个出现的名字所确定的人是其他所有人的公共祖先。

    输出


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

    样例输入

    4
    Adam Sam
    Sam Joey
    Sam Micheal
    Adam Kevin
    3
    Sam Sam
    Adam Sam
    Micheal Kevin
    

    样例输出

    Sam
    Adam
    Adam
    

    题解


    题解:http://hihocoder.com/problemset/problem/1067

    #include <map>
    #include <cmath>
    #include <cstdio>
    #include <complex>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #define ll long long
    #define inf 0
    #define PI acos(-1)
    #define bug puts("here")
    #define REP(i,x,n) for(int i=x;i<=n;i++)
    #define DEP(i,n,x) for(int i=n;i>=x;i--)
    #define mem(a,x) memset(a,x,sizeof(a))
    typedef unsigned long long ull;
    using namespace std;
    inline int read(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void Out(int a){
        if(a<0) putchar('-'),a=-a;
        if(a>=10) Out(a/10);
        putchar(a%10+'0');
    }
    const int MOD=1000000007;
    const int N=100000+5;
    int fa[N],head[N],head2[N],tot,tot2;
    bool in[N];
    map<int,int>vis2;
    int n,m;
    struct node{
        int to,nex,id;
        node(int u,int v,int ti=0):to(u),nex(v),id(ti){}
        node(){}
    }Path[N<<1],query[N<<1];
    void Addedge(int u,int v){
        Path[++tot]=node(v,head[u]);
        head[u]=tot;
    }
    void Addedge2(int u,int v,int id){
        query[++tot2]=node(v,head2[u],id);
        head2[u]=tot2;
    }
    int hashstr(char* str){
        int res=0;
        REP(i,0,strlen(str)-1){
            res=(res*233+str[i])%MOD;
        }
        return res;
    }
    int find(int x){return fa[x]==-1?x:fa[x]=find(fa[x]);}
    bool vis[N];
    int ancestor[N],ans[N];
    char name[N][20];
    void lca(int u){
        vis[u]=true;
        ancestor[u]=u;
        for(int i=head[u];i;i=Path[i].nex){
            int v=Path[i].to;
            if(vis[v]) continue;
            lca(v);
            int f1=find(u),f2=find(v);
            if(f1!=f2) fa[f2]=f1;
            ancestor[find(u)]=u;
        }
        for(int i=head2[u];i;i=query[i].nex){
            int v=query[i].to;
            if(vis[v]){
                ans[query[i].id]=ancestor[find(v)];
            }
        }
    }
    int main(){
        n=read();
        char s1[20],s2[20];
        memset(head,-1,sizeof(head));
        memset(head2,-1,sizeof(head2));
        memset(fa,-1,sizeof(fa));
        int cnt=0;
        REP(i,1,n){
            scanf("%s%s",s1,s2);
            int ha1=hashstr(s1);
            int ha2=hashstr(s2);
            if(!vis2[ha1])
                 vis2[ha1]=++cnt,strcpy(name[cnt],s1);
            if(!vis2[ha2])
                 vis2[ha2]=++cnt,strcpy(name[cnt],s2);
            ha1=vis2[ha1];ha2=vis2[ha2];
            Addedge(ha1,ha2);
            Addedge(ha2,ha1);
            in[ha2]=true;
        }
        m=read();
        REP(i,1,m){
            scanf("%s%s",s1,s2);
            int ha1=hashstr(s1);
            int ha2=hashstr(s2);
            ha1=vis2[ha1];ha2=vis2[ha2];
            Addedge2(ha1,ha2,i);
            Addedge2(ha2,ha1,i);
        }
        int root=1;
        REP(i,1,n){
            if(!in[i])root=i;
        }
        lca(root);
        REP(i,1,m){
            printf("%s
    ",name[ans[i]]);
        }
        return 0;
    }
    
  • 相关阅读:
    Python str转化成数字
    MySQL之CONCAT()的用法
    MySQL之LIMIT用法
    MySQL中LOCATE用法
    设计模式-模版方法
    设计模式-单例模式
    设计模式-桥接模式
    UML图标含义及记忆方法
    redis-分布式锁-消除竞争条件
    redis-分布式锁-刷新信号量
  • 原文地址:https://www.cnblogs.com/zsyacm666666/p/7674097.html
Copyright © 2011-2022 走看看