1. 程式人生 > >淺談LCA的線上演算法

淺談LCA的線上演算法

最近在學雙連通分量,做到一個題,是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】);

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];//查詢出的是他的祖先
}
以上就是LCA轉RMQ演算法,然後還有一個tarjan離線演算法,去學習嘍

其實ST也是tarjan的,

要換床頭畫了