Tarjan-LCA算法小记

Tarjan-LCA算法是一种离线算法。

算法描述:

DFS遍历每个节点,对于遍历到的当前节点u:

①建立以u为代表元素的集合。

②遍历与u相连的节点v,如果没有被访问过,对于v使用Tarjan-LCA算法,结束后,将v的集合并入u的集合。

③对于与u有关的询问Query(u,v),如果v被访问过,则LCA(u,v)为v所在集合的代表元素。

代码模板:

const int maxn=10005; //节点数
const int maxm=10005; //边数
const int maxq=10005; //查询数

int par[maxn];
int find(int x){return (par[x]==x)?x:(par[x]=find(par[x]));}

struct Edge{
    int u,v;
    Edge(int u=0,int v=0){this->u=u,this->v=v;}
};
vector<Edge> E;
vector<int> Ge[maxn];
void addedge(int u,int v)
{
    E.push_back(Edge(u,v));
    Ge[u].push_back(E.size()-1);
}

struct Query{
    int u,v;
    int lca;
    Query(int u=0,int v=0,int lca=0){this->u=u,this->v=v,this->lca=lca;}
};
vector<Query> Q;
vector<int> Gq[maxn];
void addquery(int u,int v,int lca)
{
    Q.push_back(Query(u,v,lca));
    Gq[u].push_back(Q.size()-1);
}

bool vis[maxn];
void LCA(int u)
{
    par[u]=u; //建立以u为代表元素的集合
    vis[u]=1;
    for(int i=0;i<Ge[u].size();i++)
    {
        Edge &e=E[Ge[u][i]]; int v=e.v;
        if(!vis[v])
        {
            LCA(v);
            par[v]=u; //将v的集合并入u的集合
        }
    }
    for(int i=0;i<Gq[u].size();i++)
    {
        Query &q=Q[Gq[u][i]]; int v=q.v;
        if(vis[v])
        {
            q.lca=find(v);
            Q[Gq[u][i]^1].lca=q.lca;
        }
    }
}

时间复杂度:

DFS遍历图O(n),枚举查询O(q),总的就是O(n+q)。

猜你喜欢

转载自www.cnblogs.com/dilthey/p/9328406.html