hihoCoder week15 最近公共祖先·二

tarjan求lca  就是dfs序中用并查集维护下,当访问到询问的第二个点u的时候  lca就是第一点的find(fa[v])

fa[v] = u; // 当v为u的儿子 且 v已经dfs完毕

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5+10;

struct node {
    int to;
    int nxt;
    int lca;
}E[N];

int n, cnt, tot, fa[N], vis[N];
map<string ,int> mp;
string s[N], s1, s2;
vector<int> son[N];
int head[N], ans[N];
void add_edge(int u,int v) 
{
    ++tot;
    E[tot].to = v;
    E[tot].nxt = head[u];
    head[u] = tot;
}


void init()
{
    for(int i=0; i<N; i++) 
        fa[i] = i;
}

int fi(int x) 
{
    return fa[x] == x ? x : fa[x] = fi(fa[x]);
}

int getId(string str)
{
    if(mp[str]) {
        return mp[str];
    }
    mp[str] = (++cnt);
    s[cnt] = str;
    return cnt;
}


void dfs(int u) 
{
    for(int i=0; i<son[u].size(); i++) {
        int v = son[u][i];
        if(vis[v]) continue;
        dfs(v);
        fa[v] = u;
    }
    vis[u] = true;
    for(int i=head[u]; i!=0; i=E[i].nxt) {
        int v = E[i].to;
        if(!vis[v]) continue;
        if(i%2) {
            E[i].lca = fi(v);
            E[i+1].lca = E[i].lca;
        }
        else {
            E[i].lca = fi(v);
            E[i-1].lca = E[i].lca;
        }
    }
}

int main()
{
    freopen("in.txt","r",stdin);
    init();
    int n; scanf("%d", &n);
    for(int i=0; i<n; i++) {
        cin >> s1 >> s2;
        int u = getId(s1);
        int v = getId(s2);
        son[u].push_back(v);
    }
    int m; scanf("%d", &m);
    for(int i=0; i<m; i++) {
        cin >> s1 >> s2;
        int u = getId(s1);
        int v = getId(s2);
        add_edge(u,v);
        add_edge(v,u);
    }
    dfs(1);
    for(int i=1;i<=m;i++) {
        cout << s[E[i*2].lca] <<endl;
    }
    return 0;
}

 

posted @ 2018-11-23 19:50  Draymonder  阅读(135)  评论(0编辑  收藏  举报