倍增 Tarjan 求LCA
----代码都是 HDU 2586 "How far away" 为例
倍增求LCA
树上倍增法。
设F[x,k] 表示x的2的k次方辈祖先,即 由x向上走2的k次方到达的节点
F[x,k]=F[F[x][k-1],k-1]
预处理: 这类似于一个动态规划的过程,阶段就是节点的深度,因此,我们可以对树进行bfs,按照层次顺序,下节点入队之前,计算它在F数组中相应的值。
基于F数组计算LCA:
1.设d[x]表示x的深度。不妨设d[x]>d[y]
2.用二进制拆分思想,把x上调到与y同一深度
3.若x=y则LCA=y
否则 把x,y同时向上调整,并保持深度一致且二者不相会。
具体来说,就是依次尝试把x,y同时向上走2的整数次方步(递减),在每此尝试中,若F[x,k]!=F[y,k],则令x=F[x,k],y=F[y,k]
4.此时x,y必定只差一步就相会了 则 LCA=fa[x] (x的父结点)
-----《算法竞赛》
#include<iostream>
#include<cstdio>
#include<vector>
#include<cmath>
#define M 40010
#define go(i,a,b) for(register int i=a;i<=b;i++)
#define go1(i,a,b) for(register int i=a;i>=b;i--)
using namespace std;
int read()
{
int x=,y=; char c; c=getchar();
while(c<''||c>'') {if(c=='-') y=-;c=getchar();}
while(c>=''&&c<='') {x=(x<<)+(x<<)+c-'';c=getchar();}
return x*y;
}
int b[M],d[M],f[M][],dis[M],T,m,n,tt,t;
struct node1 {int v,w,n;} a[M*];
void add(int u,int v,int w) {a[++tt].n=b[u];a[tt].v=v;a[tt].w=w;b[u]=tt;}
void dfs(int u)
{
int v,w;
for(int i=b[u];i;i=a[i].n)
{
v=a[i].v;w=a[i].w;
if(v==f[u][]) continue ;
f[v][]=u;
dis[v]=dis[u]+w;
d[v]=d[u]+;
go(j,,t) f[v][j]=f[f[v][j-]][j-];
dfs(v);
}
}
int lca(int u,int v)
{
if(d[u]>d[v]) swap(u,v);
go1(i,t,) if(d[f[v][i]]>=d[u]) v=f[v][i];
if(u==v) return u;
go1(i,t,) if(f[u][i]!=f[v][i]) {u=f[u][i];v=f[v][i];}
return f[u][];
}
int main()
{
T=read();
while(T--)
{
int u,v,w;
n=read();m=read();t=(int)(log(n)/log())+;
tt=; go(i,,n) {dis[i]=;d[i]=;b[i]=;}
go(i,,n-) {u=read();v=read();w=read();add(u,v,w);add(v,u,w);}
d[]=;dfs();
go(i,,m)
{u=read();v=read();printf("%d\n",dis[u]+dis[v]-*dis[lca(u,v)]);}
}
return ;
}
Tarjan求LCA
算法本质是使用并查集对“向上标记法”的优化。离线算法。复杂度为O(m+n)。
-----《算法竞赛》
画图非常清晰明了啊
#include<iostream>
#include<cstdio>
#include<vector>
#define M 40010
#define go(i,a,b) for(register int i=a;i<=b;i++)
using namespace std;
int read()
{
int x=,y=; char c; c=getchar();
while(c<''||c>'') {if(c=='-') y=-;c=getchar();}
while(c>=''&&c<='') {x=(x<<)+(x<<)+c-'';c=getchar();}
return x*y;
}
vector<int> q[M][];
int b[M],ans[M],dis[M],f[M],fa[M];
int tt,n,m,T;
struct node1 {int v,w,n;} a[M*];
void add(int u,int v,int w) {a[++tt].n=b[u];a[tt].v=v;a[tt].w=w;b[u]=tt;}
int find(int x) {if(fa[x]==x) return x; return fa[x]=find(fa[x]);}
void tarjan(int u)
{
f[u]=;int v,w,id;
for(int i=b[u];i;i=a[i].n)
{
v=a[i].v;w=a[i].w;
if(f[v]) continue ;
dis[v]=dis[u]+w;
tarjan(v);
fa[v]=u;
}
for(int i=;i<q[u][].size();i++)
{
v=q[u][][i];id=q[u][][i];
if(f[v]==)
{ans[id]=dis[u]+dis[v]-*dis[find(v)];}
}
f[u]=;
}
void init()
{
tt=;
go(i,,n)
{
fa[i]=i;q[i][].clear();q[i][].clear();dis[i]=;f[i]=;b[i]=;
}
}
int main()
{
T=read();
while(T--)
{
n=read();m=read(); int u,v,w;
init();;
go(i,,n-)
{u=read();v=read();w=read();add(u,v,w);add(v,u,w);}
go(i,,m)
{
u=read();v=read();
q[u][].push_back(v);q[v][].push_back(u);
q[u][].push_back(i);q[v][].push_back(i);
}
tarjan();
go(i,,m) printf("%d\n",ans[i]);
}
return ;
}
倍增 Tarjan 求LCA的更多相关文章
- 倍增\ tarjan求lca
对于每个节点v,记录anc[v][k],表示从它向上走2k步后到达的节点(如果越过了根节点,那么anc[v][k]就是根节点). dfs函数对树进行的dfs,先求出anc[v][0],再利用anc[v ...
- 图论分支-倍增Tarjan求LCA
LCA,最近公共祖先,这是树上最常用的算法之一,因为它可以求距离,也可以求路径等等 LCA有两种写法,一种是倍增思想,另一种是Tarjan求法,我们可以通过一道题来看一看, 题目描述 欢乐岛上有个非常 ...
- Tarjan求LCA
LCA问题算是一类比较经典的树上的问题 做法比较多样 比如说暴力啊,倍增啊等等 今天在这里给大家讲一下tarjan算法! tarjan求LCA是一种稳定高速的算法 时间复杂度能做到预处理O(n + m ...
- 详解使用 Tarjan 求 LCA 问题(图解)
LCA问题有多种求法,例如倍增,Tarjan. 本篇博文讲解如何使用Tarjan求LCA. 如果你还不知道什么是LCA,没关系,本文会详细解释. 在本文中,因为我懒为方便理解,使用二叉树进行示范. L ...
- tarjan求lca的神奇
题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...
- 【Tarjan】洛谷P3379 Tarjan求LCA
题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...
- HDU 2586 倍增法求lca
How far away ? Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)To ...
- SPOJ 3978 Distance Query(tarjan求LCA)
The traffic network in a country consists of N cities (labeled with integers from 1 to N) and N-1 ro ...
- 倍增法求LCA
倍增法求LCA LCA(Least Common Ancestors)的意思是最近公共祖先,即在一棵树中,找出两节点最近的公共祖先. 倍增法是通过一个数组来实现直接找到一个节点的某个祖先,这样我们就可 ...
随机推荐
- (二)Jmeter各部件的作用
JMeter主要组件介绍 1.测试计划(Test Plan)是使用 JMeter 进行测试的起点,它是其它 JMeter 测试元件的容器. 2.线程组(Thread Group)代表一定数量的并发用户 ...
- PHP 配置默认SSL CA证书
1.从CURL 官网下载CA 证书(当然也可以选择自己创建SSL CA证书,详情参考 https://blog.csdn.net/scuyxi/article/details/54898870 ,或自 ...
- 使用 MQTTnet 快速实现 MQTT 通信
1 什么是 MQTT ? MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是 IBM 开发的一个即时通讯协议,有可能成为物联网的重要组成部分.MQT ...
- 【uoj#228】基础数据结构练习题 线段树+均摊分析
题目描述 给出一个长度为 $n$ 的序列,支持 $m$ 次操作,操作有三种:区间加.区间开根.区间求和. $n,m,a_i\le 100000$ . 题解 线段树+均摊分析 对于原来的两个数 $a$ ...
- OpenSSL 自签名证书
通过下面9步,可以轻松生成自签名证书. 1.安装.部署OpenSSL 略 2.创建文件夹(下面通常root文件夹).用来放即将创建的各种证书等.如:I:\Key10.167.219.64 3.在roo ...
- 深入理解JAVA虚拟机JVM
深入理解JAVA虚拟机JVM Java 虚拟机(Java virtual machine,JVM)是运行 Java 程序必不可少的机制.java之所以能实现一次编写到处执行,也就是因为jVM.原理:编 ...
- 初次使用http打不开页面,使用https打开过后使用http协议又能正常访问
http协议为什么打不开https站点 在访问一个https的站点,比如 https://www.aaa.com,首次访问时,访问的地址是 http://www.aaa.com,(不加S),出现的是网 ...
- MT【157】至少一个小于1
若函数$f(x)=x^2+ax+b$有两个不等实数根$x_1,x_2$,且$1<x_1<x_2<3$,那么$f(1),f(3)中$ ( )A.只有一个小于1 B.至少 ...
- BZOJ2529 [Poi2011]Sticks 【贪心】
题目链接 BZOJ2529 题解 要组成三角形,当且仅当最长边长度小于另两条边之和 我们就枚举最长边,另两条边当然是越大越好 我们将所有边排序,从小枚举并记录各个颜色的最长边 当枚举到当前边时,找到除 ...
- BZOJ4416 [Shoi2013]阶乘字符串 【序列自动机 + 状压dp】
题目链接 BZOJ4416 题解 建立序列自动机,即预处理数组\(nxt[i][j]\)表示\(i\)位置之后下一个\(j\)出现的位置 设\(f[i]\)表示合法字符集合为\(i\)的最短前缀,枚举 ...