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

#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. Ubuntu-Python2.7安装 scipy,numpy,matplotlib

    sudo apt-get install python-scipy sudo apt-get install python-numpy sudo apt-get install python-matp ...

  2. (转)Hibernate框架基础——一对多关联关系映射

    http://blog.csdn.net/yerenyuan_pku/article/details/52746413 上一篇文章Hibernate框架基础——映射集合属性详细讲解的是值类型的集合(即 ...

  3. Android(java)学习笔记206:JNI之工具快速开发步骤

    下面通过一个案例说明一下,利用工具jni快速开发步骤 1.新建一个Android工程,命名为"03_对int数组加1",如下: 2. 在MainActivity.java中对add ...

  4. std list/vector sort 自定义类的排序就是这么简单

    所以,自己研究了一下,如下:三种方式都可以,如重写<,()和写比较函数compare_index.但是要注意对象和对象指针的排序区别. 1.容器中是对象时,用操作符<或者比较函数,比较函数 ...

  5. Python 爬虫爬取今日头条街拍上的图片

    # 今日头条--街拍 import requests from urllib.parse import urlencode import os from hashlib import md5 from ...

  6. vuecli开发项目,文件打包后,appjs/vendorjs文件过大

    项目上线后,浏览器第一次加载会特别特别慢,network中看到vendorjs文件1.9M,不慢才怪. echarts按需引入后,也有1.1M左右,由于对vue脚手架理解不深,自己扒了大量的文档,又测 ...

  7. Oracle 常用目录结构(10g)

    大多数情况下,了解Oracle常用目录结构,将大大提高数据库管理与维护的工作效率,本文介绍了Oracle 10g 的常用目录. OFA: 下面给出Oracle 最优灵活体系结构OFA(Optimal ...

  8. java加载properties文件的六种方法总结

    java加载properties文件的六种方法总结 java加载properties文件的六中基本方式实现 java加载properties文件的方式主要分为两大类:一种是通过import java. ...

  9. 洛谷 4768 LOJ 2718「NOI2018」归程

    [题解] 本题有多种做法,例如可持久化并查集.kruskal重构树等. kruskal重构树的做法是这样的:先把边按照海拔h从大到小的顺序排序,然后跑kruskal建立海拔的最大生成树,顺便建krus ...

  10. 【Codeforces 404C】Restore Graph

    [链接] 我是链接,点我呀:) [题意] 每个节点的度数不超过k 让你重构一个图 使得这个图满足 从某个点开始到其他点的最短路满足输入的要求 [题解] 把点按照dep的值分类 显然只能由dep到dep ...