树链剖析求LCA
一 LCA问题
LCA问题即树上最近公共祖先,求解LCA问题经典的解法有倍增,tarjan(万能的Tarjan),当然还有我们的树链剖析了
二 前置芝士
在求解lCA之前,我们要知道树链剖析的一些基础知识,在树链剖析中分为轻重链剖析和长短链剖析
重点:相依值最大的一个点(可以是根据子树的大小或者子树的深度进行选择),每一个点的子节点只有一个重节点
轻节点:除重点之外的节点都是轻节点
重链:指的是重点和其父节点相连的那个边
轻链:指的是轻节点和其父节点相连的那个边
顶点:指的是沿重链回溯到最前的那个顶点,遇到轻链便终止,所以轻节点的顶点就是它的本身
三 思路
在进行两个点的查询时候,如果两个节点的顶点不同,说明这两个点不在一条链上,此时我们需要让深度较深的那个点跳转到它的顶点的父节点,重复上面的操作,知道两个顶点跳转到一条链上,输出深度较浅的那个点。
当两个点的顶点不同的时候,两个点不在一条链上,如果使得次点为其顶点的父节点,才有可能在一条链上,并且是不会超过的,因为父节点只是向上增加一个位置,而两个不在一条链,起码是存在一个位置以上的差距。当两个点在一条链上时,前面的点一定是他们的LCA
![6011632897515_.pic](/Users/chengjiajun/Desktop/markdown截屏/6011632897515_.pic.jpg)
四 code
1 求重链和重点
void DFS1(int x)
{
size[x] = 1;
dep[x] = dep[f[x]] + 1;
for(int i = head[x];i;i = E[i].next){
int to = E[i].to;
if(to == f[x]) continue;
f[to] = x;
DFS1(to);
size[x] += size[to];
if(!son[x]||size[son[x]] < size[to]) son[x] = to;
// son[x]是这个x的最重子节点
}
}
2 求顶点
void DFS2(int x,int tv)
{
top[x] = tv;
if(son[x]) DFS2(son[x],tv);
for(int i = head[x];i;i = E[i].next)
{
int to = E[i].to;
if(to == f[x]||to == son[x]) continue;
DFS2(to,to);
}
}
3 LCA
while (top[x]!=top[y])
{
if(dep[top[x]] >= dep[top[y]]) x = f[top[x]];
else y = f[top[y]];
}
printf("%d\n",dep[x]<dep[y]?x:y);