先贴上学习的文章:
洛谷P3379题解1
倍增讲解
在用Tarjan算法求LCA时会出现超时的现象,因为是一层一层的往上跳,于是就有了用倍增法求LCA,是层地往上跳。复杂度:O(nlogn)
按2的倍数跳,不过是从大到小跳,32,16,8,4,2,1。原因是从小到大跳会出现“悔棋”的现象:
从小到大:5!=1+2+4
从大到小:5=4+1
5<32 (不跳)
5<16(不跳)
5<8(不跳)
5>=4(向上跳4格到1)
1<2(不跳)
1>=1(向上跳1格到0)
step1:预处理
目标:
可知:fa[x][0]=x的父节点
fa[x][1]=fa[x的父节点][0]=fa[fa[x][0]][0]
fa[x][i]=fa[fa[x][i-1]][i-1]
原因是:比如向上跳=8层:
当前i节点向上跳8/2=4=层,到达点j
再由j节点向上跳8/2=4=层,到达目的节点。(一共跳了层)
void dfs(int now,int pre){
dep[now]=dep[pre]+1;
vis[now]=1;
fa[now][0]=pre;
for(int i=1;(1<
step2:常数优化
节点n向上跳的范围是[1,log2(n)]
for(int i=1;i<=n;i++){//求出log2(i)+1的值
lg[i]=lg[i-1]+(1<
可以模拟一下:
lg[1]=0+(1==1)=1
lg[2]=1+(1==1)=2
lg[3]=2+(4==3)=2
lg[4]=2+(4==4)=3
这里为什么用递推公式求log2(i)+1,而不用cmath里的函数求log2(i),原因是:
log是以e为底数, log10是以10为底数
求log2(i),则:log(i)/log(2)速度慢,不如求出log2(i)+1的值存在lg[i]数组里,需要的时候用lg[i]-1
step3:倍增LCA
有了上两步的铺垫,现在就好求多了。
求倍增LCA的思想是:
比如节点7和9,9先跳到8,此时和7是同一层,若是跳地太多到1,就会错认为1是LCA
正确的是7->4 9->8->5
fa[4][0]或fa[5][0]=3就是答案
int lca(int x,int y){
if(dep[x]dep[y]){
x=fa[x][lg[dep[x]-dep[y]]-1];
}
if(x==y)return x;
for(int k=lg[dep[x]];k>=0;k--){
if(fa[x][k]!=fa[y][k]){
x=fa[x][k];
y=fa[y][k];
}
}
return fa[x][0];
}
完结撒花✿✿ヽ(°▽°)ノ✿
上一道模板题:
hdu2874
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include