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