最近有一次考试有两个测试点是裸的树上带权lca,然而我那10分都没有拿到,我真菜的可以
问题简单描述:给你一棵树,树的边都有边权,有很多询问,求两点之间的距离
首先看下面一个例子
我们以1为树根,然后我们设置一个数组dep[ ]表示从根出发每个节点的深度,例如dep[1]=1,dep[2]=2,dep[3]=2...
再设置一个数组dis[ ]表示从根节点出发到每个点的距离 ,例如dis[1]=0,dis[2]=3,dis[4]=9
假定lca(x,y)表示x和y两个节点的最近公共祖先,那么x到y的距离显然等于dis[x]+dis[y]-2*dis[lca(x,y)]
然后我们看看预处理代码
void build(int u,int fa){
for(int i=1;i<25;i++){
f[u][i]=f[f[u][i-1]][i-1];
}
for(int i=head[u];i;i=nxt[i]){
int v=to[i];
if(v==fa)continue;
dis[v]=dis[u]+wei[i];
dep[v]=dep[u]+1;
f[v][0]=u;
build(v,u);
}
}
其中f[i][j] 表示从i节点出发向上走步到达的节点显然f[u][0]=u的父节点 然后递归下去就可以求出来了
然后就是lca函数了
int lca(int x,int y){
if(dep[x]<dep[y]){
swap(x,y);
}
for(int i=24;i>=0;i--){
if(dep[f[x][i]]>=dep[y]){
x=f[x][i];
}
if(x==y)return x;
}
for(int i=24;i>=0;i--){
if(f[x][i]!=f[y][i]){
x=f[x][i],y=f[y][i];
}
}
return f[x][0];
}
我们假定dep[x]>=dep[y] 那么首先我们要让x和y的深度一样,然后再一起向上跳找到最近公共祖先
然后下面一个for循环就是一起跳了,注意:这里一定要从大到小for
至于理解的话,就是如果从小到大for,刚开始跳了一点点步数,后面还差一点点,然后一下又跳很多次,就跳不到了
所以要从大到小for,根据任何一个数一定能表示成二进制的形式,然后就一定能找到。
ok!!!