Tarjan演算法求LCA(最近公共祖先)

2021-06-27 17:01:22 字數 1738 閱讀 1341

lca的離線演算法。複雜度為o(n+q)。

這個演算法充分利用了dfs樹的結構。

對於每個節點u,關於它的詢問(u,v)只有兩種。(假設先dfs(u)後dfs(v))

1、v在u的子樹內。

此時lca(u,v) = u.

2、v不在u的子樹內。

⑴假設v在u的父親的另一棵子樹內。

此時lca(u,v) = father[u].

⑵如果不滿足條件⑴,則v可能在u的父親的父親的另一棵子樹內。

而此時lca(u,v) = father[ father[u] ].

⑶……觀察一下,是不是發現了什麼呢?

沒錯,不論是哪種情況,lca(u,v)都與u和father[ ]有某種關係。我們能不能抓住這種關係呢?

我們繼續觀察,一直向上取father[ ],貌似和並查集的find操作很像呢。

我們用並查集的角度依次考慮上面的情況試試看。

1、v在u的子樹內。

此時dfs(u)還在棧中,沒有執行完,此時沒有向上取father[ ],說明此時u是根。

2、v不在u的子樹內。

⑴假設v在u的父親的另一棵子樹內。

此時的dfs(u)已經執行完並出棧。此時向上取了一次father[ ],說明此時u的父親是根。

⑵如果不滿足條件⑴,則v可能在u的父親的父親的另一棵子樹內。

同理,此時dfs(u的父親)也已經執行完並出棧。此時向上取了兩次father[ ],說明此時u的父親的父親是根。

⑶……

綜上,我們只要保證當dfs(u)在棧中的時候,u是根;當dfs(u)不在棧中的時候,father[u]是根就行了。

[cpp]view plain

copy

#include 

#include 

#include 

using

namespace

std;  

#define filein  freopen("in.ads","r",stdin)

#define fileout freopen("out.ads","w",stdout)

#define n 155

#define m 22555

struct

vertex  

v[n],qv[n];  

struct

edge  

e[m],qe[m];  

inttop,pre[n];  

bool

used[n];  

void

init()  

introot(

intx)  

void

union(

inta,

intb)  

void

add_edge(

intu,

intv)  

void

add_qedge(

intu,

intv)  

void

tarjan(

intu)  

for(int

i=v[u].head;i!=-1;i=e[i].next)  

}  intmain()  

scanf("%d"

,&q);  

while

(q--)  

tarjan(1);  

}  return

0;  

}  

**

Tarjan演算法求LCA

題源 這個題還是debug了好久。1.呼叫函式中如果要更改外部資料需要傳遞引用,其實傳遞引用往往效率更高,以後要多加注意這一點。2.忘寫並查集了 捂臉逃 3.題目要求的是距離而不是lca,認真審題。貼 include include include define maxn 100005 define...

Tarjan離線演算法求最近公共祖先(LCA)

arjan離線演算法求lca介紹 前言 首先,本人搞懂tarjan求最近公共祖先 lca 也是瀏覽了大量其他大牛的文章,若是看了本文仍未弄懂的,可以嘗試自己做一下模板題 裸題 hdu2586,自己用資料去感受一下,或者可以換篇文章再看,或許他的文章更對你的 胃口 一 概念介紹 1 最近公共祖先 對於...

Tarjan離線演算法 (LCA最近公共祖先)

tarjan離線演算法是利用並查集和dfs來達到離線處理的目的 我們都知道,對於一棵樹,後序遍歷一遍,訪問它的根的時機一定是後與它的孩子的。換一句話,當開始遍歷它的根節點的時候,它遍歷過的孩子的公共祖先一定是這個根而這也就成為了我們解題的思想。由於是需要對整樹進行dfs,所以tarjan需要在所有資...