关于lca和它的倍增求法

lca,即最近公共祖先.

最近公共祖先的概念是在一棵树上的,就像下面这棵树:


这棵树里,3和6的最近公共祖先就是1,3和2的最近公共祖先就是2.

也就是说,两个点i和j的最近公共祖先是连接它们的最短路径上深度最小的节点.

所以,我们有一个最坏时间复杂度为O(n)的算法求lca.

我们先找到深度更深的节点,然后追溯它的父亲直至它的祖先k与另一节点的深度相同.

接下来,我们同时追溯两个节点的父亲,直至这两个父亲是同一个节点.

那么这个节点就是lca.

代码如下:

void dfs(int k=1){
  if (k==1) d[k]=1,father[k]=0;
  for (int i=lin[k];i;i=e[i].next)
    if (e[i].y!=father[k]){
      father[e[i].y]=k;
      d[e[i].y]=d[k]+1;
      dfs(e[i].y);
    }
}      //预处理
inline int query(int x,int y){
  if (d[x]<d[y]) swap(x,y);
  while (d[x]!=d[y]) x=father[x];
  while (x!=y) x=father[x],y=father[y];
  return x;
}      //查询 

那么这串代码一般来说比较快,但是有个恶心数据给你出了个链状树,这就会退化成O(n).

所以,我们还有更稳定的算法.

主要有三种算法能够较快的求出lca:倍增,RMQ,tarjan.

这里介绍倍增,是一种在线算法.

倍增的预处理是O(nlog(n)),查询O(log(n)).

那么它的思想是倍增,grand[i][k]记录的是i节点的2^k倍祖先.(这里将父亲定义为1倍祖先,爷爷作为2倍祖先,依次类推).

那么预处理就只需要多预处理一个grand数组.

跟ST算法很像,大概是这样的:

void dfs(int k,int f){
  d[k]=d[f]+1;
  grand[k][0]=f;
  for (int i=1;(1<<i)<=d[k];i++)
    grand[k][i]=grand[grand[k][i-1]][i-1];
  for (int i=lin[k];i;i=e[i].next)
    if (e[i].y!=f) dfs(e[i].y,k);
}      //预处理

那么查询进行同样的操作,先是到达同一深度.

到达同意深度,我们可以先算这两个点的高度差.

然后用高度差的二进制为1的位i都跳到grand[x][i].

大概代码是这样的:

  if (d[x]<d[y]) swap(x,y);
  int c=d[x]-d[y];      //算出高度差
    for (int k=0;(1<<k)<=c;k++)      //只要这一位在最高位之后
      if (c&(1<<k)) x=grand[x][k];      //这一位为1,往上跳 

那么同时向上跳.

那么倍增同时向上跳是需要注意,只有grand[x][k]和grand[y][k]不等我们才跳.

因为若他们相等了,不一定是最近的.

最后跳完了,还要判断一下相不相等,在选择返回x和father[x].

像这样:

  for (c=19;c>-1;c--)
    if (grand[x][c]!=grand[y][c]) x=grand[x][c],y=grand[y][c];      //不等,往上跳 
  if (x==y) return x;
  else return grand[x][0];

那么完整的查询代码如下:

inline int query(int x,int y){
  if (d[x]<d[y]) swap(x,y);
  int c=d[x]-d[y];      //算出高度差
    for (int k=0;(1<<k)<=c;k++)      //只要这一位在最高位之后
      if (c&(1<<k)) x=grand[x][k];      //这一位为1,往上跳 
  for (c=19;c>-1;c--)
    if (grand[x][c]!=grand[y][c]) x=grand[x][c],y=grand[y][c];      //不等,往上跳 
  if (x==y) return x;
  else return grand[x][0];
}      //查询 

好,那么这样就差不多了.

至于另外两个算法,我以后学了再写.

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/80198925