zoukankan      html  css  js  c++  java
  • LCA(最近公共祖先)之倍增算法

    概述

    对于有根树T的两个结点u、v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u、v的祖先且x的深度尽可能大。

    如图,3和5的最近公共祖先是1,5和2的最近公共祖先是4

    在本篇中我们先介绍一下倍增算法

    我们需要一个数组de[i]来表示每一个节点i的深度,用另一数组parent[i][j]来表示每一节点j向上走2的i次方是哪个节点

    我们首先在初始化中算出每个点的深度和它的上一个点是什么(用parent[0][i]表示)

    在此后我们进行倍增的处理:parent[1][j]=parent[0][parent[0][j]]......parent[i+1][j]=parent[i][parent[i][j]]

    当然如果已经走到根节点了,就将其它的parent全设为0

    然后我们就可以搞lca了:给你两个点想x,y,让y成为深的那个,如果x,y深度不等就让y倍增地往上跳。

    当x,y深度相等时凡是它俩不相等就倍增地跳,最后它们中任意一个的父节点及他们的最近公共祖先

    模板

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<cctype>
    #include<cmath>
    #include<cstdlib>
    #include<queue>
    #include<ctime>
    #include<vector>
    #include<set>
    #include<map>
    #include<stack>
    using namespace std;
    const int LOG=20;
    int head[1000100],nxt[1000100],to[1000100],cnt;
    int de[500010];
    int parent[LOG+3][500010];
    inline void read(int &x){
          int f=1;x=0;char s=getchar();
          while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
          while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+s-'0';s=getchar();}
          x*=f;
    }
    inline void add(int x,int y){
          nxt[++cnt]=head[x];to[cnt]=y;head[x]=cnt;
          nxt[++cnt]=head[y];to[cnt]=x;head[y]=cnt;
    }
    inline void dfs(int now,int dep,int be)
    {     parent[0][now]=be;de[now]=dep;
          for(int i=head[now];i;i=nxt[i])
             if(to[i]!=be)dfs(to[i],dep+1,now);
    }
    inline int lca(int x,int y)
    {     if(de[x]>de[y])swap(x,y);
          for(int i=LOG;i>=0;i--)
             if(de[y]-de[x]>=(1<<i))y=parent[i][y];
          if(x==y)return x;
          for(int i=LOG;i>=0;i--)
             if(parent[i][x]!=parent[i][y])x=parent[i][x],y=parent[i][y];
          return parent[0][x];
    }
    int main()
    {     int n,m,s,i,j,k,p,q;
          read(n),read(m),read(s);
          for(i=1;i<n;i++){
              int x,y;
              read(x),read(y);
              add(x,y);
          }
          dfs(s,0,0);
          for(i=0;i<=LOG;i++)
             for(j=1;j<=n;j++)
                if(parent[i][j]<=0)parent[i+1][j]=-1;
                  else parent[i+1][j]=parent[i][parent[i][j]];
          for(i=1;i<=m;i++){
              int x,y;
              read(x),read(y);
              printf("%d ",lca(x,y));
          }
          return 0;
    }

  • 相关阅读:
    POJ2376 Cleaning Shifts
    百度首页图标
    NOIP2016换教室
    CH3803扑克牌
    【POJ2723】Get Luffy Out
    【USACO13DEC】 最优挤奶
    【SP2916】Can you answer these queries V
    【线段树】各种模板集合
    【SCOI2013】摩托车交易
    【CF1174D】 Ehab and the Expected XOR Problem
  • 原文地址:https://www.cnblogs.com/yzxverygood/p/7881656.html
Copyright © 2011-2022 走看看