LCA 離線tarjan模板

2022-09-02 16:48:17 字數 1586 閱讀 6333

/*

*演算法引入:

*樹上兩點的最近公共祖先;

*對於有根樹的兩個結點u,v,最近公共祖先lca(t,u,v)表示乙個結點x,滿足x是u,v的祖先且x的深度盡可能大;

*對於x來說,從u到v的路徑一定經過點x;

* *演算法思想:

*tarjan_lca離線演算法;

*tarjan演算法基於dfs的框架,對於新搜到的乙個結點,首先建立由這個結點構成的集合,再對當前結點的每個子樹進行搜尋;

*每搜尋完一棵子樹,則可確定子樹內的lca詢問都已解決,其他的lca詢問的結果必然在這個子樹之外;

*這時把子樹所形成的集合與當前結點的集合合併,並將當前結點設為這個集合的祖先;

* *這時把當前結點也設為已被檢查過的,同時可以處理有關當前結點的lca詢問;

*如果有乙個從當前結點到結點v的詢問,且v已經被檢查過;

*則由於進行的是dfs,當前結點與v的最近公共祖先一定還沒有被檢查;

*而這個最近公共祖先的包含v的子樹一定已經搜尋過了,那麼這個最近公共祖先一定是v所在集合的祖先;

* *演算法步驟:

*對於每乙個結點:

*(1)建立以u為代表元素的集合;

*(2)遍歷與u相連的結點v,如果沒有被訪問過,對於v使用tarjan_lca演算法,結束後將v的集合併入u的集合;

*(3)對於與u有關的詢問(u,v),如果v被訪問過,則結果就是v所在集合的代表元素;

* *演算法示例:

*hdu2586(how far away?)

* *題目大意:

*求樹上任兩點間的距離;

* *演算法思想:

*先dfs一遍,求出到根節點的dis;

*對於某個詢問,求u和v的lca,然後res[i]=d[u]+d[v]-2*d[lca(u,v)];

* **/struct

node;

intfa[maxn];

int head[maxn*2

];int qhead[maxm];//

詢問bool

vis[maxn];

ll d[maxn];

ll res[maxm];

node edge[n*2

];node qedge[m];

//詢問邊

intn,m;

intcnt1,cnt2;

int findfa(int

x)inline

void addedge(int u,int v,int

w)inline

void addqedge(int u,int

v)void dfs(int u,int

fa,ll w)

}void tarjan_lca(int u)

}for(int i=qhead[u];i!=-1;i=qedge[i].next)

}}void

solve()

while(m--)

dfs(

1,-1,0

); tarjan_lca(1);

}int

main()

}

LCA離線演算法tarjan

lca演算法 lca least common ancestor 是指在一棵樹中,距離兩個點最近的兩者的公共節點。也就是說,在兩個點通往根的道路上,肯定會有公共的節點,我們就是要求找到公共的節點中,深度盡量深的點。還可以表示成另一種說法,就是如果把樹看成是乙個圖,這找到這兩個點中的最短距離。本文先介...

LCA 離線tarjan演算法

對於最近公共祖先問題,我們先來看這樣乙個性質,當兩個節點 u,v 的最近公共祖先是x時,那麼我們可以確定的說,當進行後序遍歷的時候,必然先訪問完x的所有子樹,然後才會返回到x所在的節點。這個性質就是我們使用tarjan演算法解決最近公共祖先問題的核心思想。同時我們會想這個怎麼能夠保證是最近的公共祖先...

LCA的離線演算法Tarjan

總的來說是深度遍歷。以根為節點建立並查集。比如說求p,v的lca。當訪問到p的時候檢查v是否已經訪問過。如果訪問過,那麼他們的lca就是v現在所在的並查集裡面的元素。如果沒有訪問到。那麼等到v訪問到的時候可以操作一下。充分利用了遞迴這個操作,所以不必要儲存以前的東西,自然而然的就將u裡面的所有的子節...