這是LCA演算法中的一種,Tarjan演算法

其實這麼說也有點不對,應該是Tarjan+DFS進行解決

LCA又稱為最近公共祖先

那麼什麼是最近公共祖先:

在一棵沒有環的樹上,每個節點肯定有其父親節點和祖先節點

而最近公共祖先,就是兩個節點在這棵樹上深度最大公共祖先節點

換句話說,最近公共祖先就是兩個點在這棵樹上距離最近的公共祖先節點

那麼我們該如何去求這個最近公共祖先呢?

通常初學者都會想到最簡單粗暴的一個辦法:

對於每個詢問,遍歷所有的點,時間複雜度為O(n*q),很明顯,n和q一般都是挺大的

常用的求LCA的演算法有:

Tarjan/DFS+ST/倍增

後兩個演算法都是線上演算法,也很相似,時間複雜度在O(logn)~O(nlogn)之間

有的題目是可以用線段樹來做的,但是其程式碼量很大,

況且時間複雜度也挺高,在O(n)~O(nlogn)之間,但是優點在於簡單粗暴

關於Tarjan演算法:

1、  Tarjan演算法是離線演算法,需要預先讀入所有的詢問。

2、  Tarjan是基於並查集的。

3、  這個Tarjan演算法跟求橋求連通塊那個tarjan演算法不一樣(事實上tarjan發明過很多演算法,貌似都叫tarjan演算法)

4.任選一個點為根節點,從根節點開始。

5.遍歷該點u所有子節點v,並標記這些子節點v已被訪問過。

6.若是v還有子節點,返回2,否則下一步。

7.合併v到u上。

8.尋找與當前點u有詢問關係的點v。

9.若是v已經被訪問過了,則可以確認u和v的最近公共祖先為v被合併到的父親節點a。

遍歷就是用DFS,優化則是用並查集。

例題:

洛谷P3379

傳送門

這題就可以用Tarjan演算法進行求解

當然,和Tarjan在一起連用的就是DFS

程式碼挺難的,好多:

#include<cstdio>
#include<cstring>
using namespace std;
inline int read(){
int a; scanf("%d",&a);
return a;
}
const int N=5e5+;
int head[N],n,m,S,tot(),Qtot(),f[N],ans[N],Qhead[N];
bool vis[N];
struct E{int to,next;}e[N<<];
struct Q{int ver,next;}q[N<<];
inline void add_edge(int u,int v){
e[tot]=(E){
v,head[u]
};
head[u]=tot++;
e[tot]=(E){
u,head[v]
};
head[v]=tot++;
}
inline void add_query(int u,int v){
q[Qtot]=(Q){
v,Qhead[u]
};
Qhead[u]=Qtot++;
q[Qtot]=(Q){
u,Qhead[v]
};
Qhead[v]=Qtot++;
}
inline void add_ans(int A,int query_num){
ans[query_num>>]=A;
}
void print_ans(){
for(int i=;i<m;i++)
printf("%d\n",ans[i]);
}
int find(int x){
return x==f[x]?x:f[x]=find(f[x]);
}
inline void RAB()
{
n=read();
m=read();
S=read();
int u,v;
memset(head,-,sizeof(head));
for(int i=;i<n;i++)
u=read(),v=read(),add_edge(u,v);
memset(Qhead,-,sizeof(Qhead));
for(int i=;i<=m;i++)
u=read(),v=read(),add_query(u,v);
for(int i=;i<=n;i++)
f[i]=i;
memset(vis,true,sizeof(vis));
}
void dfs(int s,int fa)
{
for(int i=head[s],to=e[i].to;i!=-;i=e[i].next,to=e[i].to)
if(to!=fa)
dfs(to,s),f[find(to)]=s;
vis[s]=false;
for(int i=Qhead[s],ver=q[i].ver;i!=-;i=q[i].next,ver=q[i].ver)
if(!vis[ver]) add_ans(find(ver),i);
}
int main()
{
RAB();
dfs(S,);
print_ans();
return ;
}

程式碼還沒註釋,為難各位了,後期我會補上的。