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

题目描述

如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。

输入输出格式

输入格式:

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

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

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

输出格式:

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

输入输出样例

输入样例#1: 复制

5 5 4
3 1
2 4
5 1
1 4
2 4
3 2
3 5
1 2
4 5

输出样例#1: 复制

4
4
1
4
4

说明

时空限制:1000ms,128M

数据规模:

对于30%的数据:N<=10,M<=10

对于70%的数据:N<=10000,M<=10000

对于100%的数据:N<=500000,M<=500000

样例说明:

该树结构如下:

第一次询问:2、4的最近公共祖先,故为4。

第二次询问:3、2的最近公共祖先,故为4。

第三次询问:3、5的最近公共祖先,故为1。

第四次询问:1、2的最近公共祖先,故为4。

第五次询问:4、5的最近公共祖先,故为4。

故输出依次为4、4、1、4、4。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=500000+5;
inline int read()
{int x=0,f=1; char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-')f=-1; ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}return x*f;
}
int n,m,s,num;
int f[maxn][30],head[maxn],dep[maxn];
bool vis[maxn];
struct node
{int next,to;
}e[maxn<<1];
inline void add(int from,int to)
{e[++num].next=head[from];e[num].to=to;head[from]=num;
}
inline void dfs(int x,int d)
{vis[x]=1;dep[x]=d;for(int i=head[x];i;i=e[i].next){int to=e[i].to;if(!vis[to]){f[to][0]=x;dfs(to,d+1);}}
}
inline int lca(int a,int b)
{if(dep[a]<dep[b]){int t=a;a=b;b=t;}int d=dep[a]-dep[b];for(int i=20;i>=0;i--)if(d&(1<<i)) a=f[a][i];if(a==b) return a;for(int i=20;i>=0;i--)if(f[a][i]!=f[b][i]){a=f[a][i];b=f[b][i];}return f[a][0];
}
int main()
{n=read();m=read();s=read();for(int i=1;i<n;i++){int x,y;x=read();y=read();add(x,y);add(y,x);}dfs(s,1);for(int j=1;j<=20;j++)for(int i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1];for(int i=1;i<=m;i++){int a,b,ans;a=read();b=read();ans=lca(a,b);printf("%d\n",ans);}return 0;
}

树上倍增

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=500000+5;
inline int read()
{int x=0,f=1; char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-')f=-1; ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}return x*f;
}
int n,m,s,num,qnum;
int father[maxn],head[maxn],qhead[maxn],a[maxn][3];
bool vis[maxn];
struct node
{int next,to;
}e[maxn<<1];
struct qnode
{int next,to,k;
}q[maxn<<1];
inline void add(int from,int to)
{e[++num].next=head[from];e[num].to=to;head[from]=num;
}
inline void qadd(int from,int to,int k)
{q[++qnum].next=qhead[from];q[qnum].to=to;q[qnum].k=k;qhead[from]=qnum;
}
inline int find(int x)
{if(x!=father[x]) father[x]=find(father[x]);return father[x];
}
inline void merge(int x,int y)
{int r1=find(x);int r2=find(y);father[r1]=r2;
}
void tarjan(int x)
{vis[x]=1;for(int i=qhead[x];i;i=q[i].next){int to=q[i].to,k=q[i].k;if(vis[to]) a[k][2]=find(to);}for(int i=head[x];i;i=e[i].next){int to=e[i].to;if(!vis[to]){tarjan(to);merge(to,x);}}
}
int main()
{n=read();m=read();s=read();for(int i=1;i<=n;i++) father[i]=i;for(int i=1;i<n;i++){int x,y;x=read();y=read();add(x,y);add(y,x);}for(int i=1;i<=m;i++){a[i][0]=read();a[i][1]=read();qadd(a[i][0],a[i][1],i); qadd(a[i][1],a[i][0],i);}tarjan(s);for(int i=1;i<=m;i++)printf("%d\n",a[i][2]);return 0;
}

tarjan算法

转载于:https://www.cnblogs.com/huihao/p/7793221.html

洛谷P3379 【模板】最近公共祖先(LCA)相关推荐

  1. 最近公共祖先(LCA)

    最近公共祖先 向上标记法 树上倍增 Tarjan发明的算法 转化为求区间最小值问题 最近公共祖先问题是树中的常考问题,比如我们有一棵树(可以是多叉的),两个点的最近公共祖先就是字面的意思,比如说6.5 ...

  2. POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA)...

    POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA) Description A ...

  3. 【C++】最近公共祖先 LCA

    最近公共祖先 百科名片 简单引入 LCA的算法 暴力枚举法 Tarjan离线算法 倍增算法 例题: 题目描述 输入描述 输出描述 样例输入 样例输出 代码 百科名片 最近公共祖先 Lowest Com ...

  4. 最近公共祖先 (LCA) [No. 21]

    问题: 给定一个二叉树,找到两个节点NA, NB的最近公共祖先(LCA). 比如对于下图,4 和 7 的 LCA 是6, 1和13的LCA 是 8. 我们这里先考虑一般的二叉树(BT),然后再考虑这个 ...

  5. 树上倍增法求最近公共祖先LCA

    LCA,最近公共祖先,这个东西有很多作用,因此,如何高效求出LCA就成了一个热点的讨论话题. 下面所有的讨论都以图中这棵树为例子. 先来了解下什么是倍增吧,倍增其实就是二分的逆向,二分是逐渐缩小范围, ...

  6. 图论--最近公共祖先LCA

    最近公共祖先LCA LCA(Least Common Ancestors),即最近公共祖先,是指这样一个问题:在有根树中,找出某两个结点u和v最近的公共祖先(另一种说法,离树根最远的公共祖先) 最近公 ...

  7. 洛谷·【模板】点分树 | 震波【including 点分树

    初见安-这里是传送门:洛谷P6329 [模板]点分树 | 震波 一.点分树 其实你会点分治的话,点分树就是把点分治时的重心提出来重新连城一棵树. 比如当前点是u,求出子树v的重心root后将root与 ...

  8. 最近公共祖先LCA 【专题@AbandonZHANG】

    参考: <算法艺术与信息学竞赛> --- 刘汝佳 博客:http://blog.163.com/kevinlee_2010/blog/static/16982082020120794613 ...

  9. 专题·树链剖分【including 洛谷·【模板】树链剖分

    初见安~~~终于学会了树剖~~~ [兴奋]当初机房的大佬在学树剖的时候我反复强调过:"学树剖没有前途的!!!" 恩.真香. 一.重链与重儿子 所谓树剖--树链剖分,就是赋予一个链的 ...

最新文章

  1. 如何限制IP,通过SSH登陆linux服务器
  2. RabbitMQ指南(中)
  3. Python之tkinter:动态演示调用python库的tkinter带你进入GUI世界(计算器简单功能)
  4. CentOS7安装wdCP面板,快速搭建web运行环境(图文详解)
  5. 【收藏】docker的privileged 与 k8s的privileged 设置方式
  6. HTML5协议的,HTML5新增协议:WebSocket协议的实例
  7. Visual studio 打包
  8. Python的Pexpect详解 [图片]
  9. 紧急预警:wls9_async_response.war组件漏洞的延续
  10. linq判断集合中相同元素个数_java----Collection集合常用方法
  11. 软件质量管理体系 type:pdf_制造型企业构建完整的质量管理体系的思路要点
  12. bash脚本编程之十 函数
  13. sql智能语法提示插件 sql prompt 10
  14. Win系统新建文件夹快捷键
  15. 初学Java,搭建Java环境以及创建Java程序
  16. matlab函数power,Matlab中Powergui介绍.pdf
  17. 多智能体强化学习Multi agent,多任务强化学习Multi task以及多智能体多任务强化学习Multi agent Multi task概述
  18. 将网站放到桌面快捷方式
  19. 个人永久性免费-Excel催化剂功能第105波-批量调整不规范的图形对象到单一单元格内存储...
  20. 知识蒸馏——pytorch实现

热门文章

  1. sencha touch 入门学习资料大全
  2. OpenResty(nginx)操作redis的初步应用
  3. 苹果手机计算机键盘声音怎么办,苹果键盘声音怎么设置大小声
  4. 华为鸿蒙宣传悟空视频_给华为“鸿蒙”打Call,家居头条号探讨短片《悟空》获50万阅读...
  5. um是代表什么意思_白玫瑰代表什么意思 居然有这么多含义
  6. 信息系统项目的应急预案方案_从环评到验收、排污许可证、应急预案,都应在项目什么阶段开展? 先后顺序是什么?...
  7. 备战2020年双十一,刷喵币靠这一个自动化脚本就够了!
  8. 测试面试题集-MySQL数据库灵魂拷问
  9. 借贷平台Liquity昨日共有超300个Troves被清算
  10. NFT平台 NFTb将推出新版本,支持社会公益事业