算法模板——倍增求LCA

来源:互联网 发布:淘宝上远程解锁可靠吗 编辑:程序博客网 时间:2024/05/29 18:36

LCA是什么?
最近公共祖先,就是树上的两个点它们深度最大(离根节点最远)的公共祖先。

算法
1. 朴素算法。时间复杂度O(n×q)。并没有实际意义。
2. 倍增算法。时间复杂度O((n+q)logn)

倍增算法
它的特点是:每次向祖先跳的距离,不是1,而是2k,这样可以省很多时间。
记录每个点的fai,j,表示i号节点向根跳2j步的点,如果跳过了根记为0。那么显然,第一步是要把要询问的两个节点都跳到同一深度,第二步同时往根跳。这样就找到了这两个点的LCA。

代码

#include <cstdio>#include <algorithm>const int maxn=500000;inline int read(){  int x=0,f=1;  char ch=getchar();  while((ch<'0')||(ch>'9'))    {      if(ch=='-')    {      f=-f;    }      ch=getchar();    }  while((ch>='0')&&(ch<='9'))    {      x=x*10+ch-'0';      ch=getchar();    }  return x*f;}inline int print(int x,int mode=0){  if(!mode)    {      if(!x)    {      putchar('0');      return 0;    }      if(x<0)    {      putchar('-');      x=-x;    }    }  if(x)    {      print(x/10,1);      putchar(x%10+'0');    }  return 0;}struct tree{  int pre[maxn*2+10],now[maxn+10],son[maxn*2+10],tot;  int deep[maxn+10],fa[maxn+10][20];  int ins(int a,int b)//建图  {    tot++;    pre[tot]=now[a];    now[a]=tot;    son[tot]=b;    return 0;  }  int dfs(int u,int father)//预处理,把每个点的fa都处理出来  {    deep[u]=deep[father]+1;    fa[u][0]=father;    for(int i=1; i<=19; i++)      {    fa[u][i]=fa[fa[u][i-1]][i-1];      }    int j=now[u];    while(j)      {    int v=son[j];    if(v!=father)      {        dfs(v,u);      }    j=pre[j];      }    return 0;  }  int lca(int x,int y)//求LCA  {    if(deep[x]<deep[y])      {    std::swap(x,y);      }    for(int i=19; i>=0; i--)      {    if(deep[fa[x][i]]>=deep[y])      {        x=fa[x][i];//将深度大点的往上跳,当然不能跳过另一个点      }      }    if(x==y)      {    return x;//如果找到答案了退出      }    for(int i=19; i>=0; i--)      {    if(fa[x][i]!=fa[y][i])//同时向上跳,当然不能跳到一起去      {        x=fa[x][i];        y=fa[y][i];      }      }    return fa[x][0];//最后再跳到一起,那么这个点一定是LCA  }};tree t;int n,m,root;int main(){  n=read();  m=read();  root=read();  for(int i=1; i<n; i++)    {      int a=read(),b=read();      t.ins(a,b);      t.ins(b,a);    }  t.dfs(root,0);  while(m--)    {      print(t.lca(read(),read()));      putchar('\n');    }  return 0;}