lca之倍增簡單講解
lca代指least common ancestor,翻譯過來就是最近公共祖先
如下圖,x和y的最近公共祖先就是二號節點
那麼,如何來求這個最近公共祖先呢?
1.暴力演算法
讓x和y一步一步向上爬,一直爬到相遇為止
x: 4->3->2
y: 6->5->2
可是這樣暴力實在是太慢了,我們要想辦法優化它
於是就有了倍增求解lca
2.倍增
倍增的意思就是按二的此方遞增,比如: 1->2->4->8->16......
在x與y向上爬找祖先時,我們不用每次向上爬乙個,而是向上爬2^n個,這樣程式的效率會高很多
怎麼倍增呢?我們需要從大到小跳,比如: 32->16->8->4...... 為什麼不是從小到大?應為可能會跳過,出現「悔棋」的情況
舉個例子:
我們要求x(5號節點)與y(10號節點)的 lca
倍增的時候,我們發現y的深度比x的深度要小,於是現將y跳到8號節點,使他們深度一樣:
這個時候,x和y的深度就相同了,於是我們按倍增的方法一起去找lca
我們知道n(10)之內最大的二的次方是8,於是我們向上跳8個單位,發現跳過了。
於是我們將8/2變成4,還是跳過了。
再將4/2變成2,跳到了0號節點。
雖然這時跳到了lca,但是如果直接if(x==y)就確定的話,程式無法判斷是剛好跳到了還是跳過了,應為跳過了x也等於y
於是我們需要剛好跳到lca的兒子上,然後判斷if(x的爸爸==y的爸爸)來確定lca
由於每乙個數都可以分解為幾個2^n的和(不信自己試),所以他們一定會跳到lca的兒子上
於是我們就找到了lca啦!
3.預處理
明白了基本思路之後,我們就開始寫程式了
可是在寫lca之前,我們還得進行預處理
要處理些什麼呢?
1.每乙個點的深度,以便到時候判斷
2.每乙個點2^i級的祖先,以便到時候倍增跳
於是我們用乙個dep陣列來記錄每乙個點的深度,再用乙個fa[i][j]表示節點i的2^j級祖先
dep陣列的更新就是他爸爸的深度+1,但是如何更新fa陣列呢?
fa[i][j]=fa[fa[i][j-1]][j-1]
這個式子是什麼意思呢?
fa[i][j]就是i的2^j級祖先,那fa[i][j-1]就是i的2^(j-1)級祖先。
又因為我們知道2^(j-1)+2^(j-1)=2^j,i的2^(j-1)級祖先的2^(j-1)級祖先 就是i的2^j級祖先。
這就是這句話的意思。**如下:
void dfs(int x,int4.lca主函式過程在上面已經講過了,直接上**:father) //x為當前節點,father為他的爸爸
for(int i=0;i) //列舉與他相鄰的邊(我用的是vector存圖)
} return
;}
int lca(int u,int5.完整**下面是模板題洛谷p3379的**:v) //u,v就相當於先講的x和y
}if(u==v) //如果u剛好等於v,即他們已經變成了同乙個點
for(int i=(int)(log(n)/log(2));i>=0;i--) //(int)(log(n)/log(2))就是n以內最大的2的次方,從最大的開始倍增
}return fa[u][0
]; //返回他們的爸爸,即是lca
}
#include #include其他題目:#include
#include
#include
#include
using
namespace
std;
const
int maxn=500005
;vector
e[maxn];
int n,m,s,dep[maxn],fa[maxn][21
];int read() //
快讀
while
(isdigit(ch))
return ans*flag;
} void dfs(int x,int father) //
x為當前節點,father為他的爸爸
for(int i=0;i//
列舉與他相鄰的邊(我用的是vector存圖)
} return;}
int lca(int u,int v) //
u,v就相當於先講的x和y
}if(u==v) //
如果u剛好等於v,即他們已經變成了同乙個點
for(int i=(int)(log(n)/log(2));i>=0;i--) //
(int)(log(n)/log(2))就是n以內最大的2的次方,從最大的開始倍增
}return fa[u][0]; //
返回他們的爸爸,即是lca
}int
main()
dfs(s,
0); //
預處理
for(int i=1;i<=m;i++)
return0;
}
洛谷p3884 二叉樹問題
洛谷p2420 讓我們異或吧
洛谷p3398 倉鼠找sugar
LCA倍增講解
這道題值得一刷 題解裡的巨佬都用tarjan 窩太難了 實際上是他們太巨了 本人 馬蜂 碼風獨特,請見諒 include include include include using namespace std inline intread while ch 0 ch 9 return x f inl...
講解 模板 最近公共祖先(LCA)(倍增)
閱讀須知 我認為讀者已經掌握 或了解 了 倍增思想 樹 圖 的基本概念及簡單實現 存圖與建圖 dfs 嗯,我們來看看最近公共祖先 lca 的一種實現方式 倍增。話說什麼是最近公共祖先呢?emmm 大家如果知道樹的話,應該就知道父親節點與兒子節點了吧,那麼祖先就是父親的父親的父親的 總之在同一條樹鏈上...
倍增LCA複習
時間過去了如此之久,我連倍增lca都不怎麼記得了,要粗事啊。首先預處理層數和每個節點的父親,然後預處理p陣列,p i,j 表示i向上第2 j個祖先。最後對於每個詢問x,y先把x,y變成同一層數的 x或y向上走直到兩個層數相等 然後x,y同時向上走,直到x和y的父親相同位置。自 1.dfs預處理出所有...