Tarjan 算法求 LCA / Tarjan 算法求强连通分量

Posted zcplayground

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Tarjan 算法求 LCA / Tarjan 算法求强连通分量相关的知识,希望对你有一定的参考价值。




洛谷P3379 【模板】最近公共祖先(LCA)

#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include <set>
#include <stack>
#include <map>
#include<vector>
using namespace std;
const int maxn = 5e5 + 5;
struct query
{
    int x;
    int y;
    int lca;
}query[maxn];
int fa[maxn];
bool vis[maxn];
int deep[maxn];
vector<int> G[maxn];
vector<int> Q[maxn];

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

int find(int x)
{
    if (fa[x] == x)
        return x;
    else
        return fa[x] = find(fa[x]);
}

void Union(int v, int u)
{
    int vfa = find(v), ufa = find(u);
    if (vfa == ufa)return;
    else fa[v] = u;
}

void tarjan(int u)
{
    vis[u] = true;
    for (auto qid : Q[u]) {
        if (query[qid].x == u) {
            if (vis[query[qid].y]) {
                query[qid].lca = find(query[qid].y);
            }
        }
        else
        {
            if (vis[query[qid].x]) {
                query[qid].lca = find(query[qid].x);
            }
        }
    }
    for (auto v : G[u]) {
        if (vis[v])
            continue;
        deep[v] = deep[u] + 1;
        tarjan(v);
        Union(v, u);
    }
}

int main()
{
    init();
    int n, m, s;
    scanf_s("%d%d%d", &n, &m, &s);
    int x, y;
    for (int i = 1; i < n; i++)
    {
        scanf_s("%d%d", &x, &y);
        G[x].push_back(y);
        G[y].push_back(x);
    }
    for (int i = 1; i <= m; i++)
    {
        scanf_s("%d%d", &query[i].x, &query[i].y);
        Q[query[i].x].push_back(i); // 对于节点 x 来说有一个编号为 i 的询问
        Q[query[i].y].push_back(i);
    }
    tarjan(s);
    for (int i = 1; i <= m; i++)
    {
        printf("%d
", query[i].lca);
    }
    for (int i = 1; i <= n; i++)
    {
        printf("节点 %d 的深度是 %d
", i, deep[i]);
    }
}

FOJ 1628 计算公共祖先的个数

#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include <set>
#include <stack>
#include <map>
#include<vector>
using namespace std;
const int maxn = 5e5 + 5;
struct query
{
    int x;
    int y;
    int lca;
}query[maxn];
int fa[maxn];
bool vis[maxn];
int deep[maxn];
vector<int> G[maxn];
vector<int> Q[maxn];

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

int find(int x)
{
    if (fa[x] == x)
        return x;
    else
        return fa[x] = find(fa[x]);
}

void Union(int v, int u)
{
    int vfa = find(v), ufa = find(u);
    if (vfa == ufa)return;
    else fa[v] = u;
}

void tarjan(int u)
{
    vis[u] = true;

    for (auto qid : Q[u]) {
        if (query[qid].x == u) {
            if (vis[query[qid].y]) {
                query[qid].lca = find(query[qid].y);
            }
        }
        else
        {
            if (vis[query[qid].x]) {
                query[qid].lca = find(query[qid].x);
            }
        }
    }
    for (auto v : G[u]) {
        if (vis[v])
            continue;
        deep[v] = deep[u] + 1;
        tarjan(v);
        Union(v, u);
    }
}

int main()
{
    init();
    int n, k, m;
    int x, y;
    scanf_s("%d", &n);
    for (int i = 1; i <= n; i++)
    {
        scanf_s("%d", &k);
        for (int j = 1; j <= k; j++)
        {
            scanf_s("%d", &y);
            G[i].push_back(y);
            G[y].push_back(i);
        }
    }
    scanf_s("%d", &m);
    for (int i = 1; i <= m; i++) // 离线处理
    {
        scanf_s("%d%d", &query[i].x, &query[i].y);
        Q[query[i].x].push_back(i); // 对于节点 x 来说有一个编号为 i 的询问
        Q[query[i].y].push_back(i);
    }
    tarjan(1);
    /*for (int i = 1; i <= m; i++)
    {
        printf("%d
", query[i].lca);
    }
    for (int i = 1; i <= n; i++)
    {
        printf("节点 %d 的深度是 %d
", i, deep[i]);
    }*/
    for (int i = 1; i <= m; i++)
    {
        printf("%d
", deep[query[i].lca] + 1);
    }
}

以上是关于Tarjan 算法求 LCA / Tarjan 算法求强连通分量的主要内容,如果未能解决你的问题,请参考以下文章

Tarjan之求LCA

Tarjan求LCA

(转载)LCA问题的Tarjan算法

LCA(tarjan)

[POJ1330]Nearest Common Ancestors(LCA, 离线tarjan)

tarjan,树剖,倍增求lca