首页 > 代码库 > 浅谈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的,

要换床头画了

浅谈LCA的在线算法