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序+倍增

洛谷P3379 【模板】最近公共祖先(LCA)(dfs序+倍增)的更多相关文章

  1. [模板] 最近公共祖先/lca

    简介 最近公共祖先 \(lca(a,b)\) 指的是a到根的路径和b到n的路径的深度最大的公共点. 定理. 以 \(r\) 为根的树上的路径 \((a,b) = (r,a) + (r,b) - 2 * ...

  2. 【树链剖分】洛谷P3379 树链剖分求LCA

    题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...

  3. 洛谷3320 SDOI2015寻宝游戏(set+dfs序)(反向迭代器的注意事项!)

    被\(STL\)坑害了一个晚上,真的菜的没救了啊. 准确的说是一个叫\(reverse\ iterator\)的东西,就是我们经常用的\(rbegin()\) 有一个非常重要的性质 在反向迭代器中,+ ...

  4. 【洛谷 p3379】模板-最近公共祖先(图论--倍增算法求LCA)

    题目:给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 解法:倍增. 1 #include<cstdio> 2 #include<cstdlib> 3 #include ...

  5. 图论2 最近公共祖先LCA

    模板 吸取洛谷P3379的教训,我决定换板子(其实本质都是倍增是一样的),把vector换成了边表 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下 ...

  6. 最近公共祖先 lca (施工ing)

    声明 咳咳,进入重难点的图论算法之一(敲黑板): 题目: 洛谷 P3379 先放标程,施工ing,以后补坑!!!(实在太难,一个模板这么长 [ 不过好像还是没有 AC自动机 长哎 ],注释都打半天,思 ...

  7. Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集)

    Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集) Description sideman做好了回到Gliese 星球的硬件准备,但是sideman的导航系统还没有完全设计好.为 ...

  8. POJ 1470 Closest Common Ancestors(最近公共祖先 LCA)

    POJ 1470 Closest Common Ancestors(最近公共祖先 LCA) Description Write a program that takes as input a root ...

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

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

随机推荐

  1. android菜鸟学习笔记11----Intent的两点补充

    关于Intent的两点补充: 1.隐式Intent启动组件,会有一个Intent解析的过程,若找不到能够处理该Intent的组件,程序就会异常终止.一个合理的做法是,在使用Intent实例启动组件如: ...

  2. vc2013使用经验

    1 find all reference功能需要visual assist的帮助 vs2013自己的查找不行,所以可以安装visual assist X,这样的话,就可以支持快速准确的referenc ...

  3. linux中查看python的安装路径

    方法1:whereis python 查看所有python的路径,不止一个 方法2:which python 查看当前使用的python路径

  4. Java多线程系列 基础篇04 线程中断

    1. 中断线程 中断可以理解为线程的一个标志位属性,它表示一个运行中的线程是否被其他线程进行了中断操作,其他线程通过调用该线程的interrupt()方法对其进行中断操作,线程通过检查自身是否被中断来 ...

  5. Contiki进程间的交互

    之前都是从各个模块开始看起,从底层开始看起.应该改变一下思路,从高往下看,站得高看得远. 一.Main函数 源码:contiki-release-2-7\platform\stm32test\cont ...

  6. .NET中Eval()方法大全

    <%# Bind("Subject") %> //绑定字段<%# Container.DataItemIndex + 1%> //实现自动编号<%# ...

  7. 网站桌面端和手机端不同url的设置

    你的网站在搜索引擎中表现怎样很大程度上依赖于你的你的网站对于不同设备上的设计. 下面介绍了怎样基于URL构造来优化你的网站对于搜索引擎的支持. 决定你网页的URL构造 Determine the UR ...

  8. str_2.判断两个字符串是否互为旋转词

    1. 字符串str的前面任意部分挪到后面形成的字符串叫做字符串str的旋转词 $str1 = "2ab1"; $str2 = "ab12"; $ret = is ...

  9. storm源码剖析(3):topology启动过程

    storm的topology启动过程是执行strom jar topology1.jar MAINCLASS ARG1 ARG2 鉴于前面已经分析了脚本的解析过程,现在重点分析topology1.ja ...

  10. bzoj 4503 两个串 快速傅里叶变换FFT

    题目大意: 给定两个\((length \leq 10^5)\)的字符串,问第二个串在第一个串中出现了多少次.并且第二个串中含有单字符通配符. 题解: 首先我们从kmp的角度去考虑 这道题从字符串数据 ...