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。

这篇讲的不错,link一下:https://www.cnblogs.com/kousak/p/9192094.html

因为使用了vector作为临接表,效率上比前向星慢了些,开了O2优化过的。

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define MAX 500005
using namespace std;
typedef long long ll; int t;
int f[MAX],dep[MAX];
int in[MAX],out[MAX];
vector<int> v[MAX]; inline void dfs(int pre,int x,int s){
in[x]=++t;
dep[x]=s;
for(int i=;i<v[x].size();i++){
int to=v[x][i];
if(to==pre) continue;
f[to]=x;
dfs(x,to,s+);
}
out[x]=++t;
}
inline int lca(int x,int y){
if(dep[x]>dep[y]){
int temp=x;
x=y;
y=temp;
}
if(in[x]<=in[y]&&out[y]<=out[x]){
return x;
}
while(!(in[x]<=in[y]&&out[y]<=out[x])){
x=f[x];
}
return x;
}
int main()
{
int n,m,s,i,j;
int x,y;
scanf("%d%d%d",&n,&m,&s);
for(i=;i<n;i++){
scanf("%d%d",&x,&y);
v[x].push_back(y);
v[y].push_back(x);
}
t=;f[s]=s;
dfs(-,s,);
while(m--){
scanf("%d%d",&x,&y);
printf("%d\n",lca(x,y));
}
return ;
}

纯dfs序(有时会T)

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define MAX 500005
using namespace std;
typedef long long ll; int t;
int f[MAX][],dep[MAX];
int in[MAX],out[MAX];
vector<int> v[MAX]; void dfs(int pre,int x,int s){
in[x]=++t;
dep[x]=s;
for(int i=;i<v[x].size();i++){
int to=v[x][i];
if(to==pre) continue;
f[to][]=x;
dfs(x,to,s+);
}
out[x]=++t;
}
int lca(int x,int y){
if(dep[x]>dep[y]){
int temp=x;
x=y;
y=temp;
}
if(in[x]<=in[y]&&out[y]<=out[x]){
return x;
}
for(int i=;i>=;i--){
int fx=f[x][i];
if(!(in[fx]<=in[y]&&out[y]<=out[fx])){
x=fx;
}
}
return f[x][];
}
int main()
{
int n,m,s,i,j;
int x,y;
scanf("%d%d%d",&n,&m,&s);
for(i=;i<n;i++){
scanf("%d%d",&x,&y);
v[x].push_back(y);
v[y].push_back(x);
}
t=;f[s][]=s;
dfs(-,s,);
for(i=;i<=;i++){
for(j=;j<=n;j++){
f[j][i]=f[f[j][i-]][i-];
}
}
while(m--){
scanf("%d%d",&x,&y);
printf("%d\n",lca(x,y));
}
return ;
}

dfs序+倍增

最新文章

  1. 【HTML5】浅析HTML5应用程序缓存(ApplicationCache)
  2. Javascript DOM基础(一)概念
  3. HDU-2196 Computer (树形DP)
  4. 修改hive内存限制
  5. KEIL段协定
  6. String, StringBuilder 与StringBuffer的区别与联系
  7. android 巧用资源文件(不断积累)
  8. 使用Dotfuscator加密混淆程序以及如何脱壳反编译
  9. Python算术运算
  10. Restful风格
  11. Docker介绍及使用
  12. 前端学习之HTML
  13. HDU 1257 最少拦截系统(思路题)
  14. iframe父页面获取子页面元素方法
  15. java_manual的一点体会
  16. centos7下rsync+crontab定期同步备份
  17. Maven私服
  18. 解决NIOS II工程移动在磁盘上位置后project无法编译问题
  19. nio案例一:个简单的客户-服务的案例
  20. Java访问重定向接口

热门文章

  1. 【WinForm】创建自定义控件(转)
  2. 九度OJ 1159:坠落的蚂蚁 (模拟、排序)
  3. linux c编程:进程间通信
  4. python仪表盘
  5. 51Nod 1084 矩阵取数问题 V2 —— 最小费用最大流 or 多线程DP
  6. Android 4.0 的 GridLayout
  7. 高效上网教程---资源软件搜索技巧(搜索好用软件或者app去哪些网站)
  8. 分享知识-快乐自己:Hibernate中的 quert.list() 与 quert.iterate() 方法区别
  9. 基于node.js及express实现中间件,实现post、get
  10. listen 68 Theoretical Physicist Stephen Hawking Dies at 76