最近公共祖先 LCA (Lowest Common Ancestors)-樹上倍增

樹上倍增是求解關於LCA問題的兩個在線算法中的一個,在線算法即不須要開始所有讀入查詢,你給他什麼查詢,他都能返回它們的LCA。html

樹上倍增用到一個關鍵的數組F[i][j],這個表示第i個結點的向上2^j層的結點。在RMQ-ST中用救是這樣的數組。node

在樹上倍增中也是關鍵點。算法

如在上圖中,咱們要找結點8和7的LCA,從途中咱們能夠看出是3(這句估計是廢話)。採用倍增的思想是這樣的數組

首相判斷結點U和V是否在同一層次,便是否深度相同。由於在深度相同後這樣後,兩者就能夠同時向上跳某n層,去識別所到之點是否爲它們的LCA。ide

若是深度較大(在底下的點),跳到較高的那個點後,發現兩者重合了,那麼恭喜,LCA已經找到spa

另外底下的結點向上跳的步數也不是一步一層的,要否則太慢了。而是計算出U和V的高度差,按高度差的對數k(2^k)去跳,於是愈來愈接近高層結點,直到相等。3d

 1 if(depth[u] < depth[v])
 2     {
 3         swap(u,v);//始終讓U在最小邊,便於理解
 4     }
 5     while(depth[u] != depth[v])//兩者再也不同一高度
 6     {
 7         u = father[u][lg[ depth[u]-depth[v]]]; //u向上跳 2^(兩者高度差的對數)層
 8     }
 9     if(u==v)//重疊直接就是找到LCA
10     {
11         return u;
12     }
View Code

可是大多數狀況不是這樣的,它們每每不會重合,所以要開是同步向上跳。code

U結點到根結點的距離(U的深度爲基準),取對數後爲k,在這樣去跳2^k層是確定不會超過根上面的htm

但這樣不保證是否錯過了LCA,因此回退,k-1,從新跳2^(k-1)層,再去判斷。直到U和V不等時,它們上一層的結點必定就是LCA了。再舉個簡單的例子吧blog

1 for(int j =lg[depth[u]];j>=0;j--)//lg[depth[u]]表示u距離根結點的距離取對數
2     {
3         if(father[u][j] != father[v][j])//直到兩者所跳的地方不同
4         {
5             u = father[u][j];
6             v = father[v][j];
7         }
8     }
9     return father[u][0];//返回u的father/上一層結點就是LCA
View Code

這個LCA須要以構建好樹和計算出每一個結點的深度的條件爲基礎的。

 dfs就不細說了,這裏只說一下這個語句

1  father[curnode][j] = father[father[curnode][j-1]][j-1];

模板題傳送門

相關文章
相關標籤/搜索