求LCA——最近公共祖先 倍增算法

LCA是啥呢,LCA就是一棵树里两个节点的最近公共祖先,如下图

2号节点和3号节点的LCA就是1, 5号节点和11号节点的LCA就是2,8号节点和4号节点的lca就是4

那么怎么求LCA呢。首先要建树,然后最容易想到的就是两个节点一起向上跳,第一个相遇的节点就是LCA

输入输出格式可参考洛谷P3379 LCA模板题

输入格式:

第一行包含三个正整数N、M、S,分别表示树的结点个数、询问的个数和树根结点的序号。

接下来N-1行每行包含两个正整数x、y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树)。

接下来M行每行包含两个正整数a、b,表示询问a结点和b结点的最近公共祖先。

输出格式:

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

 

先用邻接表存路径。

void add(int x,int y)
{
    to[++cnt]=y;
    nxt[cnt]=head[x];
    head[x]=cnt;
}

int main()
{
    n=read();m=read();s=read();
    int i,x,y;
    for(i=1;i<n;i++)
    {
        x=read();y=read();
        add(x,y);
        add(y,x);
    }
    return 0;
}

存路径后,我们用dfs建树,把每个节点的深度记录下来

void dfs(int x,int fa)//fa表示父节点编号
{
    int i;
    f[x]=fa;//f[x]表示x节点的父节点
    d[x]=d[fa]+1;
    for(i=head[x];i;i=nxt[i])
        if(to[i]!=fa)
            dfs(to[i],x);
}

其次需要先把两个节点跳到同一深度,然后一起往上跳即可

int work(int x,int y)
{
    int i;
    if(d[x]<d[y])
        swap(x,y);
    while(d[x]>d[y])
    	x=f[x];//移动至同一深度
    while(x!=y)
    	x=f[x],y=f[y];
    return x;
}

以上就是暴力求LCA,以为能AC吗??妥妥的TLE!!!

那么为什么T呢?是因为一次只移动到父亲节点要跳好多次,这样太慢了!

那么怎么才能快点呢?就要用倍增了!设一个grd[x][i]数组表示x节点想上跳2的i次方后的节点。所以i<=log2(n)

这个数组怎么用呢?令d[x]>=d[y]。首先还是要跳到同一深度中,先让x跳2^20次(最大)。假设我们发现深度比y小了,这就表示跳过了,我们再试试跳2^19次,如果还过了,那就再变小。如果发现深度还没到,那就跳呗,接着我们再跳,就该试试跳2^18次了,为什么不能跳两个2^19次呢?这是以为两个2^19次就是2^20次啊,肯定可以不用跳两次相同的。这样跳就能大大减少时间了。

到同一深度后,就是两个点一起往上跳了。我们还是让两个点跳2^20次,如果发现跳完后相同了,就可以确定跳到祖先了,但不一定是最近的,所以我们先不着急跳,接着,试试跳2^19次,如果还是相同,那就再变小,如果不相同,那就跳(跟上面差不多),最后跳完,可以确定x和y再向上跳一次就是LCA了,因为我们跳的时候判定了如果跳之后相同那就不跳。但是注意,当y是x的祖先时,跳到同一深度时x==y已经是LCA了,此时就不用再往上跳了。

举个栗子,还是刚才那张图,我们模拟一下求11和7的LCA                                                                                                               

首先移动到同一深度,d[7]=3,d[11]=4,所以我们从2^20次(最大)开始,一直到2^1都不行,所以节点11跳了2^0次跳到了节点6。

接着两个节点一块儿跳,从2^20次,最后还是只能跳2^0次,变成了节点2和节点3,最终再跳一次即节点1就是LCA。

em……这个栗子有点小。。。。。。。

好了,那怎么预处理grd数组呢?我们可以在dfs建树的时候预处理,那么我们可以确定grd[x][0]就是他的爸爸,那么怎么确定grd[x][1]呢?grd[x][1]不就是爸爸的爸爸(爷爷)嘛,所以grd[x][1]=grd [ grd [ x ] [ 0 ] ] [ 0 ](为了让大家看清楚特意用空格隔开嘿嘿嘿),那么grd[x][2]呢(注意这是爷爷的爷爷,而不是爷爷的爸爸)?爷爷的爷爷不就等于grd [ grd [ x ] [ 1 ] ] [ 1 ]嘛。

以此类推,我们得出grd[x][i]=grd[ grd [ x ] [ i - 1 ] ] [ i - 1 ]。是因为2^(i-1)+2(i-1)=2^i,即往上跳两次2^(i-1)就是往上跳2^i

好了我们再捋一遍思路,邻接表+预处理grd数组+跳到相同深度+一起往上跳,代码如下。

#include <iostream>
#include <cstdio>
#include <cctype>
#include <cstring>

using namespace std;

inline int read()
{
    int f=1,x=0;
    char c=getchar();
    while(!isdigit(c)){if(c=='-')f*=-1;c=getchar();}
    while(isdigit(c)){x=x*10+c-'0';c=getchar();}
    return x*f;
}

const int N=5e5+5;
int a[N],n,m,s,to[N<<1],head[N],nxt[N<<1],grd[N][23],d[N],cnt;

void add(int x,int y)
{
    to[++cnt]=y;
    nxt[cnt]=head[x];
    head[x]=cnt;//邻接表
}

void dfs(int x,int fa)
{
    int i;
    grd[x][0]=fa;//父节点
    d[x]=d[fa]+1;
    for(i=1;i<21;i++)//其实到本题19就可以了,习惯到20整一点哈哈哈
        grd[x][i]=grd[grd[x][i-1]][i-1];//预处理grd数组
    for(i=head[x];i;i=nxt[i])
        if(to[i]!=fa)
            dfs(to[i],x);
}

int lca(int x,int y)
{
    int i;
    if(d[x]<d[y])
        swap(x,y);
    for(i=20;i>=0;i--)//从大到小枚举
        if((1<<i)<=d[x]-d[y])//1<<i就是2^i,也可以预处理成数组
            x=grd[x][i];
    if(x==y)
        return x;//当y是x的祖先时
    for(i=20;i>=0;i--)
        if(grd[x][i]!=grd[y][i])
            x=grd[x][i],y=grd[y][i];//一起往上跳
    return grd[x][0];//返回父节点
}

int main()
{
    n=read();m=read();s=read();
    int i,j,x,y;
    for(i=1;i<n;i++)
    {
        x=read();y=read();
        add(x,y);
        add(y,x);//邻接表
    }
    dfs(s,0);//预处理
    for(i=1;i<=m;i++)
    {
        x=read();y=read();
        printf("%d\n",lca(x,y));
    }
    return 0;
}

当然,遇到相应的题可再加数组,比如有时可定义dis[x][i]表示x节点向上跳2^i的距离(权),或者表示最大最小值等。

  • 9
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
智慧校园整体解决方案是响应国家教育信息化政策,结合教育改革和技术创新的产物。该方案以物联网、大数据、人工智能和移动互联技术为基础,旨在打造一个安全、高效、互动且环保的教育环境。方案强调从数字化校园向智慧校园的转变,通过自动数据采集、智能分析和按需服务,实现校园业务的智能化管理。 方案的总体设计原则包括应用至上、分层设计和互联互通,确保系统能够满足不同用户角色的需,并实现数据和资源的整合与共享。框架设计涵盖了校园安全、管理、教学、环境等多个方面,构建了一个全面的校园应用生态系统。这包括智慧安全系统、校园身份识别、智能排课及选课系统、智慧学习系统、精品录播教室方案等,以支持个性化学习和教学评估。 建设内容突出了智慧安全和智慧管理的重要性。智慧安全管理通过分布式录播系统和紧急预案一键启动功能,增强校园安全预警和事件响应能力。智慧管理系统则利用物联网技术,实现人员和设备的智能管理,提高校园运营效率。 智慧教学部分,方案提供了智慧学习系统和精品录播教室方案,支持专业级学习硬件和智能化网络管理,促进个性化学习和教学资源的高效利用。同时,教学质量评估中心和资源应用平台的建设,旨在提升教学评估的科学性和教育资源的共享性。 智慧环境建设则侧重于基于物联网的设备管理,通过智慧教室管理系统实现教室环境的智能控制和能效管理,打造绿色、节能的校园环境。电子班牌和校园信息发布系统的建设,将作为智慧校园的核心和入口,提供教务、一卡通、图书馆等系统的集成信息。 总体而言,智慧校园整体解决方案通过集成先进技术,不仅提升了校园的信息化水平,而且优化了教学和管理流程,为学生、教师和家长提供了更加便捷、个性化的教育体验。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值