【树剖求LCA】树剖知识点
不太优美但是有注释的版本:
#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】树剖知识点的更多相关文章
- 树链剖分 树剖求lca 学习笔记
树链剖分 顾名思义,就是把一课时分成若干条链,使得它可以用数据结构(例如线段树)来维护 一些定义: 重儿子:子树最大的儿子 轻儿子:除了重儿子以外的儿子 重边:父节点与重儿子组成的边 轻边:除重边以外 ...
- BZOJ1906树上的蚂蚁&BZOJ3700发展城市——RMQ求LCA+树链的交
题目描述 众所周知,Hzwer学长是一名高富帅,他打算投入巨资发展一些小城市. Hzwer打算在城市中开N个宾馆,由于Hzwer非常壕,所以宾馆必须建在空中,但是这样就必须建立宾馆之间的连接通道.机智 ...
- BZOJ-3881:Divljak (AC自动机+DFS序+树链求并+树状数组)
Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. “2 x” ...
- 【bzoj3362/3363/3364/3365】[Usaco2004 Feb]树上问题杂烩 并查集/树的直径/LCA/树的点分治
题目描述 农夫约翰有N(2≤N≤40000)个农场,标号1到N,M(2≤M≤40000)条的不同的垂直或水平的道路连结着农场,道路的长度不超过1000.这些农场的分布就像下面的地图一样, 图中农场用F ...
- 树链剖分 (求LCA,第K祖先,轻重链剖分、长链剖分)
2020/4/30 15:55 树链剖分是一种十分实用的树的方法,用来处理LCA等祖先问题,以及对一棵树上的节点进行批量修改.权值和查询等有奇效. So, what is 树链剖分? 可以简单 ...
- 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个节点的树,每个点 ...
- 【bzoj3083】遥远的国度 树链剖分+线段树
题目描述 描述zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn ...
- 浅谈求lca
lca即最近公共祖先,求最近公共祖先的方法大概有3种,其实是窝只听说过3种,这3种做法分别是倍增求lca,树剖求lca和tarjan求lca,但是窝只会前2种,所以这里只说前2种算法了. 首先是倍增求 ...
- tarjan,树剖,倍增求lca
1.tarjan求lca 思想: void tarjan(int u,int f){ for(int i=---){//枚举边 if(v==f) continue; dfs(v); //继续搜 uni ...
随机推荐
- Win10 “此环境变量太大。此对话框允许将值设置为最长2047个字符。" 解决方法。
打开注册表 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment 双击右边的 Path (RE ...
- iOS布局分类
1.线性布局: 2.集合布局: 3.单元布局: 需要考虑因素: 空间充足.空间不足时内容.尺寸的取舍.
- QuickClip—界面原型设计
1.需不需要设置用户登录/注册页? QuickClip没有提供该项功能.因为本产品为单纯的移动端视频编辑软件,是一个工具类软件.而且移动端软件本就追求的是方便快捷.简单易用,本产品不需要标识使用者的身 ...
- 01Struts 2
Struts 2 Struts2是一个基于MVC设计模式的Web应用框架,它本质上相当于一个servlet,在MVC设计模式中,Struts2作为控制器(Controller)来建立模型与视图的数据交 ...
- spring boot+mybatis+mysql增删改查分页
server: port: servlet: context-path: /springBootMybatis spring: datasource: name: test url: jdbc:mys ...
- C: 字符数组中的空去掉
#include <stdio.h> #include <string.h> int main() { char a[50] = "nearby! "; i ...
- application对象的使用
application对象的使用 制作人:全心全意 application对象用于保存所有应用程序中的公有数据.它在服务器启动时自动创建,在服务器停止时销毁.当application对象没有被销毁时, ...
- ubutun 创建左面快捷方式
#http://blog.csdn.net/jizi7618937/article/details/51012552
- 洛谷 3285 [JLOI2014]松鼠的新家
[题解] 给出一条路径,问树上的点被经过了几次. 显然树剖之后树上差分就好了. #include<cstdio> #include<algorithm> #define N 3 ...
- Codeforces 938C - Constructing Tests
传送门:http://codeforces.com/contest/938/problem/C 给定两个正整数n,m(m≤n),对于一个n阶0-1方阵,其任意m阶子方阵中至少有一个元素“0”,则可以求 ...