题意简单明了(这就是个模板)。

就是让我们找2个节点的公共祖先而已,但我们要讲的做法不是生硬的爆搜,而且直接搜好像过不去……

这次就讲我往后拖了n多天才开始学了倍增LCA。

嗯,这个题,如果2个节点的深度是不一样的,我们要把他们的深度变成一样的,变成一样的以后就开始倍增搜索。

上面的这句话为我们点明了这个题的解题方法,我们要求出每个节点的深度,每个节点2的几次方个祖先是谁,还有这棵树是什么样子的(一开始我把第一个输入的当成爸爸,wa的老惨了)。

首先第一步:创建这颗树

题目中给出了树的根节点,所以说,和根节点连接的就是第二层的节点,和第二次节点连接的就是第三层的节点……和第n-1层连接的就是第n层的节点。

虽然这个的实现很简单,但如果有同学不会,可以戳这里

树建完了,开始第二步:查找一个节点第2的i次方个祖先是谁?

有个神奇的东西叫做RMQ,和这个差不多,懂了可以去秒一下。

我们可以通过一个生活实例来思考,比如你爸爸就是你第2^0个祖先,你第2^1的祖先就是你爸爸的爸爸,你的第2^2个祖先就是你爷爷的爷爷……

可以发现,我们要求的东西可以通过已知的东西获得,这就避免了一些奇怪的模拟。

现在树建完了,每个子节点的祖先也知道了,接下来就是倍增模拟了:

就像上面说的一样,先把2个位置统一公共祖先,然后寻找。

思路都讲完了,直接放代码了:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
long long n,m,s,a,b;
long long cf[100],wz,shu=1;
long long lca[500005][30],sd[500005];
long long ans,head[500005];
struct hehe
{
long long nxt,wei;
}sz[1000005];
int add(int tou,int wei)//链式前向星真香
{
ans++;
sz[ans].wei=wei;
sz[ans].nxt=head[tou];
head[tou]=ans;
}
int dfs(int qd,int bb)//搜深度的地方
{
lca[qd][0]=bb;
for(int i=1;(1<<i)<=sd[qd];i++)//没必要就不搜了,很明白的道理嘛
{
lca[qd][i]=lca[lca[qd][i-1]][i-1];//想想祖孙三代的例子或许就明白这句话了。
}
for(int i=head[qd];i!=0;i=sz[i].nxt)//链式前向星的查找
{
if(sz[i].wei!=bb)//因为不知道谁是谁的爸爸,所以要特判一下。
{
sd[sz[i].wei]=sd[qd]+1;
dfs(sz[i].wei,qd);
}
}
}
long long start(long long x,long long y)
{
if(sd[x]<sd[y])//永远让x的深度
{
swap(x,y);
}
int i=0;
while((1<<i)<=sd[x])
{
i++;
}
i--;
if(sd[x]!=sd[y])//不等于就大步的往前走
{
for(int j=i;j>=0;j--)
{
if(sd[lca[x][j]]>=sd[y])//小心不要走过。
{
x=lca[x][j];
}
}
}
if(x==y)//x是y的子节点呢,没事了,直接输出。
{
return x;
}
for(int j=i;j>=0;j--)
{
if(lca[x][j]!=lca[y][j])//这个依旧不要走过
{
x=lca[x][j];
y=lca[y][j];
}
}
return lca[x][0];//因为倍增的奇妙,最后一定会停留在答案的下一层,上升一层就可以了。
}
int main()
{
scanf("%lld%lld%lld",&n,&m,&s);//正常的读入
sd[s]=1;
lca[s][0]=0;
for(int i=0;i<n-1;i++)
{
scanf("%lld%lld",&a,&b);
add(a,b);
add(b,a);
}
dfs(s,0);
for(int i=0;i<m;i++)
{
scanf("%lld%lld",&a,&b);
printf("%lld\n",start(a,b));//正常的运算和输出
}
return 0;
}

这个题就到这里吧,讲完了。

最新文章

  1. C语言 活动安排问题
  2. SQL SERVER 数据导出JSON
  3. delphi判断文件类型
  4. 万向节死锁 gimbal lock
  5. checkbox判断选中
  6. springMVC访问静态资源的两种方式
  7. VCL定义和使用CM_Message的原因(主要是内部控制,同时可简化参数传递,还可截住消息,统一走消息路线,还可省内存)
  8. C#/.NET使用HttpWebRequest、SqlBulkCopy从API获取数据批量插入DB
  9. This application failed to start because it could not find or load the Qt platform plugin &quot;windows&quot;
  10. PHP二分查找(递归和循环)
  11. PHP 中 const define 的区别
  12. 程序猿表白练级之Hello World
  13. 杭电ACM题单
  14. 虚拟机安装CentOS6.3及常见问题总结
  15. 记一次erlang语言bug导致rabbitmq的队列没有消费者的问题
  16. 关闭QQ右下角弹窗小程序
  17. linux audit审计(7-1)--读懂audit日志
  18. 用doxygen自动生成文档
  19. linux 查看python安装路径,版本号
  20. Python Web学习笔记之Python多线程基础

热门文章

  1. win10 VirtualBox无法打开,COM对象创建失败
  2. Flutter学习笔记(33)--GestureDetector手势识别
  3. Linux下重新设置 MySQL 的密码
  4. 微信小程序-页面栈
  5. Perl入门(一)Perl的基本类型及运算符
  6. JavaWeb网上图书商城完整项目-CommonUtils(1生成uuid,2Map转换成JavaBean)
  7. 30_栈的定义.swf
  8. git配置用户和邮箱
  9. day19__第三次作业
  10. Python进阶之浅谈内置方法