算法学习笔记(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
浙公网安备 33010602011771号