zoukankan      html  css  js  c++  java
  • hihocoder1069 最近公共祖先·三(tarjin算法)(并查集)

    #1069 : 最近公共祖先·三

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

    描述

    上上回说到,小Hi和小Ho使用了Tarjan算法来优化了他们的“最近公共祖先”网站,但是很快这样一个离线算法就出现了问题:如果只有一个人提 出了询问,那么小Hi和小Ho很难决定到底是针对这个询问就直接进行计算还是等待一定数量的询问一起计算。毕竟无论是一个询问还是很多个询问,使用离线算 法都是只需要做一次深度优先搜索就可以了的。

    那么问题就来了,如果每次计算都只针对一个询问进行的话,那么这样的算法事实上还不如使用最开始的朴素算法呢!但是如果每次要等上很多人一起的话,因为说不准什么时候才能够凑够人——所以事实上有可能要等上很久很久才能够进行一次计算,实际上也是很慢的!

    “那到底要怎么办呢?在等到10分钟,或者凑够一定数量的人两个条件满足一个时就进行运算?”小Ho想出了一个折衷的办法。

    “哪有这么麻烦!别忘了和离线算法相对应的可是有一个叫做在线算法的东西呢!”小Hi笑道。

    小Ho面临的问题还是和之前一样:假设现在小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
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    #include <climits>
    #include <cstring>
    #include <string>
    #include <set>
    #include <map>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <list>
    #include <ext/rope>
    #define rep(i,m,n) for(i=m;i<=n;i++)
    #define rsp(it,s) for(set<int>::iterator it=s.begin();it!=s.end();it++)
    #define vi vector<int>
    #define pii pair<int,int>
    #define mod 1000000007
    #define inf 0x3f3f3f3f
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    #define ll long long
    #define pi acos(-1.0)
    const int maxn=1e5+10;
    using namespace std;
    using namespace __gnu_cxx;
    const int N = 100005;
    vector<int> v[N],w[N],query[N],num[N];
    int pre[N],dist[N],ans[N];
    bool vis[N];
    int n,cnt=0;
    map<string,int>p;
    map<int,string>q;
    void Init()
    {
        for(int i=1; i<=n; i++)
        {
            v[i].clear();
            w[i].clear();
            query[i].clear();
            num[i].clear();
            pre[i] = i;
            dist[i] = 0;
            vis[i] = false;
        }
    }
    int Find(int x)
    {
        if(pre[x] != x)
            pre[x] = Find(pre[x]);
        return pre[x];
    }
    void Union(int x,int y)
    {
        x = Find(x);
        y = Find(y);
        if(x == y) return;
        pre[y] = x;
    }
    void Tarjan(int cur)
    {
        vis[cur] = true;
        int size = v[cur].size();
        for(int i=0;i<size;i++)
        {
            int tmp = v[cur][i];
            if(vis[tmp]) continue;
            Tarjan(tmp);
            Union(cur,tmp);
            //printf("!!pre[%d]=%d pre[%d]=%d
    ",cur,pre[cur],tmp,pre[tmp]);
        }
        int Size = query[cur].size();
        for(int i=0;i<Size;i++)
        {
            int tmp = query[cur][i];
            if(!vis[tmp]) continue;
            ans[num[cur][i]] =Find(tmp);
            //printf("Find[%d]=%d
    ",tmp,Find(tmp));
        }
    }
    int main()
    {
        int T,Q,x,y,z;
            scanf("%d",&n);
            Init();
            string str1,str2;
            for(int i=1;i<=n;i++)
            {
                cin>>str1;cin>>str2;
                if(!p[str1]){p[str1]=++cnt;q[cnt]=str1;}
                if(!p[str2]){p[str2]=++cnt;q[cnt]=str2;}
                v[p[str2]].push_back(p[str1]);
                v[p[str1]].push_back(p[str2]);
            }
            scanf("%d",&Q);
            for(int i=0;i<Q;i++)
            {
                cin>>str1>>str2;
                x=p[str1];y=p[str2];
                query[x].push_back(y);
                query[y].push_back(x);
                num[x].push_back(i);
                num[y].push_back(i);
            }
            Tarjan(1);
            for(int i=0;i<Q;i++)
               cout<<q[ans[i]]<<endl;
        return 0;
    }
    View Code
  • 相关阅读:
    JavaScript技巧45招(转)
    css3毛玻璃效果白边问题
    css3兼容性问题归纳
    H5页面JS调试
    js操作cookie的函数
    webkit webApp 开发技术要点总结【转】
    Android如何避免输入法弹出时遮挡住按钮或输入框
    Git使用问题汇总
    Known快速开发框架
    Visual Studio 常用快捷键
  • 原文地址:https://www.cnblogs.com/jianrenfang/p/5716462.html
Copyright © 2011-2022 走看看