1. 程式人生 > 實用技巧 >ubuntu 14.04 安裝mysql5.7

ubuntu 14.04 安裝mysql5.7

最近公共祖先

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\n",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\n",ans2,ans1);
	}
	
	return 0; 
}