算法学习笔记(LCA)

反正就记一记自己学到了什么而已,加深印象

最近公共祖先(LCA)

好吧其实现在只会倍增LCA,好像还有其他的算法(看oi-wiki)但是暂时不想学

倍增LCA流程:

第一步 

在树上用dfs预处理出每一个节点的father,用一个二维数组fa(i,j)表示节点i往上跳2j步的祖先,由常识我们就知道fa[i][j] = fa[fa[i][j - 1]][j - 1]

如果不懂那就不怪我了那就听我讲

fa[i][j]的意思在前面我已经告诉你了,那么fa[i][j - 1]不就是节点i往上跳2j-1步的祖先吗,所以这个祖先再往上跳2j-1步不就是我们要的fa[i][j]了吗就是分成两次跳嘛

是不是懂了好的我当你懂了

所以呢节点的father我们就都处理好了。那么深度的处理就是一层一层往下加而已,至于怎么dfs直接看代码吧!

 

void dfs(int u){
    for(int i = 1;i <= 16;i ++){
        fa[u][i] = fa[fa[u][i - 1]][i - 1];
    }

    for(int i = head[u];i;i = e[i].next){
        int v = e[i].to;
        if(v != fa[u][0]){
            fa[v][0] = u;
            dep[v] = dep[u] + 1;
            dfs(v);
        }
    }
}

 

 

 

第二步

我们要怎么求两个点x和y的LCA呢?让这两个点同时往上跳直到他们相同不就完事了吗

当然没有这么简单啦 这样子可能会跳过头过程自行脑补

那我们就让他们跳到LCA的儿子那嘛,然后要利用倍增的思想步长从大到小去跳就行啦

最后LCA就是fa[x][0]啦喜闻乐见代码环节

 

int LCA(int x,int y){
    if(dep[x] < dep[y]) swap(x,y);
    int t = dep[x] - dep[y];
    for(int i = 0;i <= 16;i ++) if(t & (1 << i)) x = fa[x][i];
    if(x == y) return x;
    for(int i = 16;i >= 0;i --){
        if(fa[x][i] != fa[y][i]){
            x = fa[x][i];
            y = fa[y][i];
        }
    }
    return fa[x][0];
}

 

做一道模板题试一试水

https://www.luogu.com.cn/problem/P3379

这道题比较难

https://www.luogu.com.cn/problem/P4281

 

posted @ 2021-03-11 20:44  zydbk  阅读(90)  评论(0)    收藏  举报