zoukankan      html  css  js  c++  java
  • LCA

    最近公共祖先

    1.暴力

    将点按照父子关系依次向上查询,知道两个点发生重合

    # include <stdio.h>
    # include <string.h>
    # define N  40010
    # define M 2*N
    using namespace std;
    int Next[M],head[N],ver[M],edge[M];
    int depth[N],father[M],D[M];
    int tot=-1,n,m;
    void ADD(int x,int y,int z)
    {
        ver[++tot]=y;
        edge[tot]=z;
        Next[tot]=head[x];
        head[x]=tot;
    }
    int LCA(int x,int y)
    {
        while(x!=y)
        {
            if(depth[x]>=depth[y])x=father[x];
            else y=father[y];
        }
        return x;
    }
    void dfs(int x,int fa)
    {
        int y,z;
        father[x]=fa;
        depth[x]=depth[fa]+1;
        for(int i=head[x]; ~i; i=Next[i])
        {
            y=ver[i];
            z=edge[i];
            if(y==fa)continue;
            D[y]=D[x]+z;
            dfs(y,x);//查找儿子节点
        }//此dfs是为了求得depth[]数组
    }
    int main()
    {
        int  T,x,y,z;
        register int i;
        scanf("%d%d",&n,&m);
        memset(head,0xff,sizeof(head));
        tot=-1;
        for(int i=1; i<n; i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            ADD(x,y,z);
            ADD(y,x,z);//双向边
        }
        dfs(1,-1);
        while(m--)
        {
            scanf("%d%d",&x,&y);
            printf("%d
    ",D[x]+D[y]-2*D[LCA(x,y)]);
        }
        return 0;
    }
    

    2.树上倍增

    在进行 dfs 的时候处理出每个节点的父子关系,在查询时以 (2^i) 为单位向上倍增,先将两个节点的深度调整一致,然后将两个点同时向上查询,最后两点重合时,该点即为两个点的LCA,同时也可结合倍增的处理一些权值的问题

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<math.h>
    #include<vector>
    #include<queue>
    #define ll long long
    
    const ll maxn=1e5+10;
    ll n,q,tot,ans1,ans2;
    ll head[maxn*2],dep[maxn];
    ll fa[maxn][22],minn[maxn][22],maxx[maxn][22];
    struct node
    {
    	ll u,v,w,nxt;
    } s[maxn*2];
    
    inline void add(ll u,ll v,ll w)
    {
    	s[++tot].v=v;
    	s[tot].w=w;
    	s[tot].nxt=head[u];
    	head[u]=tot;
    }
    
    inline void dfs(ll x,ll f)
    {
    	fa[x][0]=f;
    	dep[x]=dep[f]+1;
    	
    	for(int i=head[x];i;i=s[i].nxt)
    	{
    		ll y=s[i].v;
    		
    		if(y==f) continue;
    		
    		minn[y][0]=s[i].w;
    		maxx[y][0]=s[i].w;
    		
    		dfs(y,x);
    	}
    }
    
    inline void lca(ll x,ll y)
    {
    	if(dep[x]<dep[y]) std::swap(x,y);
    	
    	for(int i=18;i>=0;i--)
    	{
    		if(dep[fa[x][i]]>=dep[y])
    		{
    			ans1=std::max(ans1,maxx[x][i]);
    			ans2=std::min(ans2,minn[x][i]);
    			x=fa[x][i];
    		}
    	}
    	
    	if(x==y) return ;
    	
    	for(int i=18;i>=0;i--)
    	{
    		if(fa[x][i]!=fa[y][i])
    		{
    			ans1=std::max(ans1,std::max(maxx[x][i],maxx[y][i]));
    			ans2=std::min(ans2,std::min(minn[x][i],minn[y][i]));
    			
    			x=fa[x][i];
    			y=fa[y][i];
    		}
    	}
    	
    	ans1=std::max(ans1,std::max(maxx[x][0],maxx[y][0]));
    	ans2=std::min(ans2,std::min(minn[x][0],minn[y][0]));
    }
    
    int main(void)
    {
    	scanf("%lld",&n);
    	
    	memset(minn,0x3f,sizeof(minn));
    	
    	for(int i=1;i<=n-1;i++)
    	{
    		ll x,y,z;
    		scanf("%lld %lld %lld",&x,&y,&z);
    		add(x,y,z);
    		add(y,x,z);
    	}
    	
    	dfs(1,0);
    	
    	for(int j=1;j<=18;j++)
    	{
    		for(int i=1;i<=n;i++)
    		{
    			fa[i][j]=fa[fa[i][j-1]][j-1];
    			minn[i][j]=std::min(minn[i][j-1],minn[fa[i][j-1]][j-1]);
    			maxx[i][j]=std::max(maxx[i][j-1],maxx[fa[i][j-1]][j-1]);
    		}
    	}
    	
    	scanf("%lld",&q);
    	
    	for(int i=1;i<=q;i++)
    	{
    		ll x,y;
    		ans1=-maxn*maxn*maxn;
    		ans2=maxn*maxn*maxn;
    		scanf("%lld %lld",&x,&y);
    		
    		lca(x,y);
    		
    		printf("%lld %lld
    ",ans2,ans1);
    	}
    	
    	return 0; 
    }
    
  • 相关阅读:
    IDEA搭建普通java项目
    反射的学习
    解决Eclipse中文文档注释错位-处女座的悲哀!
    maven私服的搭建
    Springboot简介01
    git初识
    Servlet学习系列1
    搭建和启动javaWeb项目
    IDEA快捷键使用说明
    1.6 比较、掩码和布尔逻辑
  • 原文地址:https://www.cnblogs.com/jd1412/p/14084867.html
Copyright © 2011-2022 走看看