图论———LCA

  P3379 【模板】最近公共祖先(LCA)

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<cmath>
#include<queue> 
using namespace std;
int num=0;
int head[1000005]={0},nxt[1000005]={0},to[1000005]={0};
int f[500005][23]={0},deep[500005]={0};  //f[x][i] x向上走2的i次方步 
int n,m,r;
void add(int x,int y)
{
	nxt[++num]=head[x];
	head[x]=num;
	to[num]=y;
}
 
void dfs(int x,int fa)
{
	f[x][0]=fa; deep[x]=deep[fa]+1;
	for(int i=head[x];i;i=nxt[i]) 
	if(deep[to[i]]==0)	  dfs(to[i],x);
}


int lca(int x,int y)
{
	if(deep[x]<deep[y])  swap(x,y);              //x更深

	for(int i=22;i>=0;i--)
	if(deep[f[x][i]]>=deep[y])   x=f[x][i];      //x倍增爬到与y同层

    if(x==y)  return x;                          //y是x祖先

    for(int i=22;i>=0;i--)
    if(f[x][i]!=f[y][i])  x=f[x][i],y=f[y][i];   //一起爬呀
    
    return f[x][0];                              //找爸爸
}

 
int main()
{   
    scanf("%d%d%d",&n,&m,&r);
    int x,y;
    for(int i=1;i<n;i++)
    {
    	scanf("%d%d",&x,&y);
    	add(x,y);add(y,x);
    }                         //存图
    
    deep[0]=0;    dfs(r,0);   //简直重要的不要不要的啦
    
    for(int i=1;i<=22;i++)
    for(int j=1;j<=n;j++)
    f[j][i]=f[f[j][i-1]][i-1];//O(nlogn)的初始化
 
    for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		printf("%d\n",lca(x,y));//在线的询问
	}
    return 0;
}

在线的lca   O((m+n)log n)    离线的等我学会再说啊,呵呵

 

1.定义    F[点数][log 点数]   deep[点数]  (核心数组) 

               邻接表存图

2.无根树转有根树(有父亲 儿子关系)————dfs  (伴随着求出deep,deep同时充当b数组) F[root][0]=0;  deep[0]=0;

3.灰常重要的初始化 ————F[root][0]=0;  deep[0]=0;    

                                                    O(nlogn) 的dp     F的二维是状态啊啊

4. LCA ———— 看标程注释   22不用改 数组开够就行

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值