淺談LCA的線上演算法
阿新 • • 發佈:2019-02-17
最近在學雙連通分量,做到一個題,是LCA的,不會做就來學習了一下LCA,發現網上有好多資料,魚龍混雜。推薦一篇因為他推薦了許多文章(感興趣點選開啟))
首先先借鑑一下他的一張圖片
這基本就是這個lca的思想。
按照我的理解首先要dfs一邊求出first 【u】,deep【u】,並且記錄下first【u】所對應的u;
程式碼如下:
void dfs(int u ,int dep) { vis[u] = true; ver[++tot] = u; first[u] = tot; deep[tot] = dep; for(int i=head[u]; i!=-1; i=edge[i].next) int v = edge[i].v; if( !vis[v] ) { dfs(v,dep+1); ver[++tot] = u; deep[tot] = dep;//這兩句話表示dfs的時候還要回溯到上面 } }
然後繼續RMQ預處理,ST演算法,這個是在上面所說的部落格模板
所謂ST演算法就是
令dp【i】【j】為從下標i開始,長度為(1《《j)長的元素的最小值,那麼狀態轉移方程就是
dp【i】【j】=min{dp【i】【j-1】,dp【i+(2<<(j-1))】【j-1】}
void ST(int len) { int K = (int)(log((double)len) / log(2.0)); for(int i=1; i<=len; i++) dp[i][0] = i; for(int j=1; j<=K; j++) for(int i=1; i+_pow[j]-1<=len; i++) { int a = dp[i][j-1] , b = dp[i+_pow[j-1]][j-1]; if(deep[a] < deep[b]) dp[i][j] = a; else dp[i][j] = b; } }
RMQ,原理是令k為滿足(1<<k)<=(r-l+1)的最大整數,則以 l 開頭的,長度為2的k次方的區間長度覆蓋了查詢區間(l,r),由於是求最小值,所以沒有關係,但是如果是累加的話,就要錯,那麼他的結果就是min(dp【l】【k】,dp【r+1-(1<<k)】【k】);
以上就是LCA轉RMQ演算法,然後還有一個tarjan離線演算法,去學習嘍int RMQ(int x ,int y) { int K = (int)(log((double)(y-x+1)) / log(2.0)); int a = dp[x][K] , b = dp[y-pow[K]+1][K]; if(deep[a] < deep[b]) return a; else return b; } int LCA(int u ,int v) { int x = first[u] , y = first[v];//查找出他最先出現的地方 if(x > y) swap(x,y); int res = RMQ(x,y);//查詢出的是他祖先的下標 return ver[res];//查詢出的是他的祖先 }
其實ST也是tarjan的,
要換床頭畫了