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)。