樹上倍增是求解關於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 }
可是大多數狀況不是這樣的,它們每每不會重合,所以要開是同步向上跳。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
這個LCA須要以構建好樹和計算出每一個結點的深度的條件爲基礎的。
dfs就不細說了,這裏只說一下這個語句
1 father[curnode][j] = father[father[curnode][j-1]][j-1];