/**演算法引入:
*樹上兩點的最近公共祖先;
*對於有根樹的兩個結點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裡面的所有的子節...