在一棵沒有環的樹上,每個節點肯定有其父親節點和祖先節點,而最近公共祖先,就是兩個節點在這棵樹上深度最大的公共的祖先節點。
換句話說,就是兩個點在這棵樹上距離最近的公共祖先節點。
所以lca主要是用來處理當兩個點僅有唯一一條確定的最短路徑時的路徑。
tarjan的演算法複雜度為$o(n+q)$。
思路:每進入乙個節點u的深搜,就把整個樹的一部分看作以節點u為根節點的小樹,再搜尋其他的節點。每搜尋完乙個點後,如果該點和另乙個已搜尋完點為需要查詢lca的點,則這兩點的lca為另乙個點的現在的祖先。
先建兩個圖,乙個為樹的各條邊,另乙個是需要查詢最近公共祖先的兩節點。
建好後,從根節點開始進行一遍深搜。
先把該節點u的father設為他自己(也就是只看大樹的一部分,把那一部分看作是一棵樹),搜尋與此節點相連的所有點v,如果點v沒被搜尋過,則進入點v的深搜,深搜完後把點v的father設為點u。
深搜完一點u後,開始判斷節點u與另一節點v是否滿足求lca的條件,滿足則將結果存入陣列中。
搜尋完所有點,自動退出初始的第乙個深搜,輸出結果。
傳送:題意:有n個點的樹。m個詢問,每個詢問要求求出的lca。最終輸出某個點作為詢問中的lca出現的次數。
分析:(題意描述有點不清喵喵喵???預設輸入是父親到兒子,然後手動記錄入度,找到根節點。
1 #include2 #include3 #include4 #include5 #includepoj14706 #include7
using
namespace
std;
8const
int maxn=910
;9 typedef pairpii;
10 vectorq[maxn];
11 vectormp[maxn];
12int ans[maxn*maxn],num[maxn*maxn];
13int
f[maxn],vis[maxn],flag[maxn];
14int find(int
x)18
void lca(int
root)
27for (int i=0;i)32}
33int
main()45}
46 scanf("
%d",&m); char
ch;47
for (int i=0;i));
51q[y].push_back();52}
53for (int i=1;i<=n;i++) vis[i]=0;54
introot;
55for (int i=1;i<=n;i++) if (!flag[i])
56lca(root);
57 memset(num,0,sizeof
(num));
58for (int i=0;i;
59for (int i=1;i<=n;i++)
60if (num[i]) printf("
%d:%d\n
",i,num[i]);61}
62return0;
63 }
1.hdu2586 how far away ?
傳送:題意:求樹上兩點的最短距離。
分析:lca。
樹上最短路:$ans=dist[u]+dist[v]-2*dist[lca(u,v)]$。
1 #include2hdoj2586using
namespace
std;
3const
int maxn=4e4+10
;4 typedef pairpii;
5struct
node;
8 vectormp[maxn];
9 vectorq[maxn];
10int ans[210
],f[maxn],vis[maxn],dis[maxn],flag[maxn];
11int find(int
x)15
void lca(int
root)
25for (int i=0;i) 30}
31}32int
main());
40mp[y].push_back();
41 flag[y]=1;42
} 43
for (int i=0;i));
46q[y].push_back();47}
48int
root;
49for (int i=1;i<=n;i++) if (!flag[i])
50lca(root);
51for (int i=0;i"
%d\n
",ans[i]);52}
53return0;
54 }
2.hdu2874 connections between cities
傳送:題意:n個點,m條邊。問樹上兩點間最短路。
分析:圖是森林。lca。(卡記憶體,mle了若干發。
需要判斷未經過的點作為新的乙個樹,求解答案。
1 #include2hdoj2874using
namespace
std;
3const
int maxn=1e4+5;4
const
int maxm=1e6+5
;5 typedef pairpii;
6struct
nodemp[maxm*2];9
struct
node2q[maxm*2
];12
inthead[maxn],q_head[maxn];
13int
ans[maxm],f[maxn],dis[maxn];
14bool
vis[maxn];
15int
tot,tot2;
16void addedge(int x,int y,int
z)22
void addquery(int x,int y,int
id)28
int find(int
x)32
void lca(int
root)
42for (int i=q_head[root];i!=-1;i=q[i].nxt)47}
48}49int
main()
64for (int i=0;i)
69for (int i=1;i<=n;i++)76}
77for (int i=0;i)81}
82return0;
83 }
Tarjan演算法求LCA(最近公共祖先)
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 如果不滿...
Tarjan離線演算法 (LCA最近公共祖先)
tarjan離線演算法是利用並查集和dfs來達到離線處理的目的 我們都知道,對於一棵樹,後序遍歷一遍,訪問它的根的時機一定是後與它的孩子的。換一句話,當開始遍歷它的根節點的時候,它遍歷過的孩子的公共祖先一定是這個根而這也就成為了我們解題的思想。由於是需要對整樹進行dfs,所以tarjan需要在所有資...
最近公共祖先 LCA 的Tarjan演算法
lca t,u,v 在有根樹t中,詢問乙個距離根最遠的結點x,使得x同時為結點u v的祖先 lca問題可以用樸素的dfs方法解決,但是時間複雜度就很高了,這裡介紹一種高階一點的解決lca問題的tarjan演算法。tarjan演算法是由robert tarjan在1979年發現的一種高效的離線演算法,...