不太优美但是有注释的版本:

#include<cstdio>
#include<iostream>
using namespace std;
struct edge{
int to,ne;
}e[1000005];
int n,m,s,ecnt,head[500005],dep[500005],siz[500005],son[500005],top[500005],f[500005];
void add(int x,int y) //加边
{
e[++ecnt].to=y;
e[ecnt].ne=head[x];
head[x]=ecnt;
}
void dfs1(int x) //构造树
{
siz[x]=1; //假设当前节点仅有一个儿子
dep[x]=dep[f[x]]+1; //当前节点深度=父亲节点深度+1
for(int i=head[x];i;i=e[i].ne) //遍历所有的子节点
{
int dd=e[i].to;
if(dd==f[x])continue; //如果是父节点,则略过
f[dd]=x; //那么确定x是当前节点的父亲
dfs1(dd); //向下遍历
siz[x]+=siz[dd]; //遍历完子树之后,加上子树的大小
if(!son[x]||siz[son[x]]<siz[dd]) //如果x节点重儿子未确定或者重儿子的子树比当前遍历节点的子树小
son[x]=dd; //更新重儿子
}
} void dfs2(int x,int tv) //求重链
{
top[x]=tv; //设置x所在重链顶为tv
if(son[x])dfs2(son[x],tv); //如果x有重儿子,那么随着这条重链走
for(int i=head[x];i;i=e[i].ne)
{
int dd=e[i].to;
if(dd==f[x]||dd==son[x])continue; //如果走到父亲或者走到重儿子(已经走过重儿子,避免重复),那么跳过
dfs2(dd,dd); //开启一条新链,链顶是其本身
}
}
int lca(int x,int y)
{
while(top[x]!=top[y]) //如果二者不在同一条重链上
{
if(dep[top[x]] >= dep[top[y]]) x=f[top[x]]; //选择所在重链的顶的深度较大的点向上跳,目的是防止跳过LCA
else y=f[top[y]];
}
return dep[x] < dep[y] ?x :y; //当二者在同一条重链上的时候,选择深度较浅的点即为lca }
int main()
{
scanf("%d%d%d",&n,&m,&s);
for(int i=1;i<n;++i)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dfs1(s);
dfs2(s,s);
for(int i=1;i<=m;++i)
{
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",lca(x,y));
}
}

  

比较优美但是没注释的版本:

#include<iostream>
#include<vector>
#include<cstdio>
#include<queue>
#include<map>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<set>
#include<cstring>
using namespace std;
typedef long long ll;
const ll INF=99999999;
const int N = 500010; int n,m,s; struct edge{
int to,ne; }e[N*2]; int top[N],siz[N],son[N],fa[N],dep[N];
int head[N],ecnt = 1; void add(int x,int y)
{
e[ecnt].to = y;
e[ecnt].ne = head[x]; head[x] = ecnt++;
} void dfs1(int x)
{
siz[x] = 1;
dep[x] = dep[fa[x]] + 1; for(int i = head[x];i;i = e[i].ne){
int t = e[i].to;
if(t == fa[x]) continue;
fa[t] = x; dfs1(t);
siz[x] += siz[t];
if(!son[x]||siz[son[x]] < siz[t])
son[x] = t;
}
} void dfs2(int x,int tp)
{
top[x] = tp; if(son[x])
dfs2(son[x],tp); for(int i = head[x];i;i = e[i].ne){
int t = e[i].to;
if(t == son[x]||t == fa[x]) continue; dfs2(t,t);
} } int lca(int x,int y)
{
while(top[x] != top[y]){
if(dep[top[x]] >= dep[top[y]]) x = fa[top[x]];
else y = fa[top[y]];
}
return dep[x] < dep[y] ?x :y;
}
int main()
{ scanf("%d%d%d",&n,&m,&s);
for(int i = 1;i < n;i++){
int x,y;
scanf("%d%d",&x,&y); add(x,y);
add(y,x);
}
dfs1(s);
dfs2(s,s); for(int i = 1;i <= m;i++){
int a,b;
scanf("%d%d",&a,&b); printf("%d\n",lca(a,b));
}
return 0;
}

树剖理解容易,需要注意的是题目如果给的是双向边,e数组需要开两倍于边数

  

【树剖求LCA】树剖知识点的更多相关文章

  1. 树链剖分 树剖求lca 学习笔记

    树链剖分 顾名思义,就是把一课时分成若干条链,使得它可以用数据结构(例如线段树)来维护 一些定义: 重儿子:子树最大的儿子 轻儿子:除了重儿子以外的儿子 重边:父节点与重儿子组成的边 轻边:除重边以外 ...

  2. BZOJ1906树上的蚂蚁&BZOJ3700发展城市——RMQ求LCA+树链的交

    题目描述 众所周知,Hzwer学长是一名高富帅,他打算投入巨资发展一些小城市. Hzwer打算在城市中开N个宾馆,由于Hzwer非常壕,所以宾馆必须建在空中,但是这样就必须建立宾馆之间的连接通道.机智 ...

  3. BZOJ-3881:Divljak (AC自动机+DFS序+树链求并+树状数组)

    Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. “2 x” ...

  4. 【bzoj3362/3363/3364/3365】[Usaco2004 Feb]树上问题杂烩 并查集/树的直径/LCA/树的点分治

    题目描述 农夫约翰有N(2≤N≤40000)个农场,标号1到N,M(2≤M≤40000)条的不同的垂直或水平的道路连结着农场,道路的长度不超过1000.这些农场的分布就像下面的地图一样, 图中农场用F ...

  5. 树链剖分 (求LCA,第K祖先,轻重链剖分、长链剖分)

      2020/4/30   15:55 树链剖分是一种十分实用的树的方法,用来处理LCA等祖先问题,以及对一棵树上的节点进行批量修改.权值和查询等有奇效. So, what is 树链剖分? 可以简单 ...

  6. Bzoj 2588 Spoj 10628. Count on a tree(树链剖分LCA+主席树)

    2588: Spoj 10628. Count on a tree Time Limit: 12 Sec Memory Limit: 128 MB Description 给定一棵N个节点的树,每个点 ...

  7. 【bzoj3083】遥远的国度 树链剖分+线段树

    题目描述 描述zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn ...

  8. 浅谈求lca

    lca即最近公共祖先,求最近公共祖先的方法大概有3种,其实是窝只听说过3种,这3种做法分别是倍增求lca,树剖求lca和tarjan求lca,但是窝只会前2种,所以这里只说前2种算法了. 首先是倍增求 ...

  9. tarjan,树剖,倍增求lca

    1.tarjan求lca 思想: void tarjan(int u,int f){ for(int i=---){//枚举边 if(v==f) continue; dfs(v); //继续搜 uni ...

随机推荐

  1. 在自学css开始就遇到问题,“链入外部样式表”在多浏览器显示问题

    在自学css开始就遇到问题,“链入外部样式表”的习题,代码如下:A.被链入的CSS文件代码.css<style  type="text/css"><!--h1{b ...

  2. Linux基础之操作系统

    一.什么是操作系统 简单来说,操作系统就是一个协调.管理和控制计算机硬件资源和软件资源的控制程序. 二.操作系统存在的意义 究根结底,我们日常对计算机的管理是对计算机硬件的管理.经过近百年的时间,现代 ...

  3. (转)Hibernate框架基础——映射主键属性

    http://blog.csdn.net/yerenyuan_pku/article/details/52740744 本文我们学习映射文件中的主键属性,废话不多说,直接开干. 我们首先在cn.itc ...

  4. CAD执行一个带参数的命令(com接口VB语言)

    主要用到函数说明: MxDrawXCustomFunction::Mx_SendStringToExecute 执行一个带参数的命令.详细说明如下: 参数 说明 CString sCmaName 命令 ...

  5. 04JavaScript程序语句

    JavaScript程序语句 2.6程序控制流程 2.6.1选择结构 if <逻辑表达式> 语句 else 语句 if <逻辑表达式> { 语句组 } else { 语句组} ...

  6. PrintWriter与ServletOutputStream的区别之文件下载

    copy自:https://blog.csdn.net/weixin_37703598/article/details/803870611.out = response.getWriter(); re ...

  7. bzoj 4026 dC Loves Number Theory 主席树+欧拉函数

    题目描述 dC 在秒了BZOJ 上所有的数论题后,感觉萌萌哒,想出了这么一道水题,来拯救日益枯竭的水题资源.给定一个长度为 n的正整数序列A,有q次询问,每次询问一段区间内所有元素乘积的φ(φ(n)代 ...

  8. [angular1.6]Error: "transition superseded" ui-router 在angular1.6 报错误问题解决

    在angular1.6版本里,使用ui-router如果报这个错误,可以将ui-router升级到最近版本即可.ui-router version v0.4.2

  9. 洛谷——P3919 【模板】可持久化数组(可持久化线段树/平衡树)

    P3919 [模板]可持久化数组(可持久化线段树/平衡树) 题目背景 UPDATE : 最后一个点时间空间已经放大 标题即题意 有了可持久化数组,便可以实现很多衍生的可持久化功能(例如:可持久化并查集 ...

  10. 编译Python文件(了解)

    目录 编译Python文件(了解) 批量生成.pyc文件(了解) 编译Python文件(了解) 为了提高加载模块的速度,强调强调强调:提高的是加载速度而绝非运行速度.python解释器会在__pyca ...