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

    倍增版LCA

    lac即最近公共祖先,u和v最近公共祖先就是两节点公用的祖先中深度最大的
    比如

    其中
    lca(1,2)=4,
    lca(2,3)=4,
    lca(3,5)=1,
    lca(2,5)=4;

    如何求LCA?

    树上倍增版:

    1. 预处理每一个节点的深度depth[i];
    2. 选定两节点;
    3. 将深度大的节点往上跳,跳到与另一节点相同深度;
    4. 然后两个节点一起往上跳,直到两个节点重合;
    5. 那么这个节点就是两个节点的lca;

    那么怎么让计算机实现“跳”?

    我们可以用倍增思想
    f[i][j]表示第i个节点往上跳2^j个节点所到达的祖先
    那么
    f[i][j]=f[f[i][j-1]][j-1]
    意思是
    从i往上跳2^j个节点所到达的节点可以转化为从i往上跳2^(j-1)再往上跳2^(j-1)个,而f[i][j-1]在之前通过递推已经推出来了
    初始化Code:

    void init()
    {
        for(int j=1;j<=N;j++)
        {
            for(int i=1;i<=n;i++)
            f[i][j]=f[f[i][j-1]][j-1];
        }
    }
    

    题目

    给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。

    输入格式:

    第一行包含三个正整数N、M、S,分别表示树的结点个数、询问的个数和树根结点的序号。
    接下来N-1行每行包含两个正整数x、y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树)。
    接下来M行每行包含两个正整数a、b,表示询问a结点和b结点的最近公共祖先。

    输出格式:

    输出包含M行,每行包含一个正整数,依次为每一个询问的结果。

    输入样例#1:
        5 5 4
        3 1
        2 4
        5 1
        1 4
        2 4
        3 2
        3 5
        1 2
        4 5
    
    输出样例#1:
        4
        4
        1
        4
        4
    
    说明

    时空限制:1000ms,128M
    数据规模:
    对于30%的数据:N<=10,M<=10
    对于70%的数据:N<=10000,M<=10000
    对于100%的数据:N<=500000,M<=500000

    #include <cstdio>
    #include <iostream>
    #include <cmath>
    using namespace std;
    int head[500010],depth[500010];
    int n,m,s,cnt,f[500010][20];
    int N=0;
    bool vis[500010];
    struct Edge
    {
        int next;
        int to;
    }e[500010];
    inline int Read(){
        int x=0,f=1;char c=getchar();
        while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
        while(c>='0'&&c<='9') {x=x*10+c-'0'; c=getchar();}
        return x*f;
    }
    void add(int from,int to)
    {
        cnt++;
        e[cnt].to=to;
        e[cnt].next=head[from];
        head[from]=cnt;
    }
    void dfs(int x)
    {
        vis[x]=true;
        for(int i=head[x];i;i=e[i].next)
    	{
            int now=e[i].to;
            if(!vis[now])
    		{
    	        depth[now]=depth[x]+1;
    	        f[now][0]=x;
    	        dfs(now);
        	}
        }
    }
    void init()
    {
        for(int j=1;j<=N;j++)
        {
            for(int i=1;i<=n;i++)
            f[i][j]=f[f[i][j-1]][j-1];
        }
    }
    int lca(int x,int y)
    {
        if(depth[x]>depth[y]) swap(x,y);
        int d=depth[y]-depth[x];
        for(int i=0;i<=N;i++)
    	{
            if((1<<i) & d)
            y=f[y][i];
        }
        if(x==y) return x;
        for(int i=N;i>=0;i--)
    	{
            if(f[x][i]!=f[y][i])
    		{
                x=f[x][i];
                y=f[y][i];
            }
        }
        return f[x][0];
    }
    int main()
    {
    	n=Read();m=Read();s=Read();
    	N=log(n)/log(2)+1;
        for(int i=1;i<n;i++)
    	{
        	int x,y;
    		x=Read();y=Read();
            add(x,y);
            add(y,x);
        }
        dfs(s);
        init();
        while(m--)
    	{
        	int x,y;
    		x=Read();y=Read();
            printf("%d
    ",lca(x,y));
        }
        return 0;
    }
    

    据我所知LCA的算法不只一种,比如:
    ST表算法
    Tarjan算法
    树链剖分算法

    倍增法只是其中一种在线算法,但已经够用
    其他算法请小伙伴们自行查阅吧!

    大图预警!!!

    镇楼

  • 相关阅读:
    蓝牙音箱的连接和断开
    画一个钟表,陪着我走
    利用MediaSession发送信息到蓝牙音箱
    修改Switch 的颜色
    ViewPager PagerAdapter 的使用
    错误:android.view.InflateException: Binary XML file line #167: Binary XML file line #167: Error inflating class <unknown>
    react-project(一)
    create-react-app重建
    nodeJS连接mysql
    nodeJS问题
  • 原文地址:https://www.cnblogs.com/widerg/p/7349705.html
Copyright © 2011-2022 走看看