倍增 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)的意思是最近公共祖先,即在一棵树中,找出两节点最近的公共祖先. 倍增法是通过一个数组来实现直接找到一个节点的某个祖先,这样我们就可 ...
随机推荐
- poj 3067 Japan(树状数组求逆序数)
链接:http://poj.org/problem?id=3067 题意:左边有n个城市,右边有m个城市,建k条道路,问有这k条道路中有多少个交点. 分析:将城市按x和y从小到大排序,对于每条道路,求 ...
- GraphQL & REST API
GraphQL & REST API GraphQL https://mp.weixin.qq.com/s/X-jm7jLXWmMmLBVgHfkRiQ https://webapplog.c ...
- Dapper 事务处理
例子: using (var connection = GetOpenConnection()) using (var transaction = connection.BeginTransactio ...
- MachineLearning Exercise 4 :Neural Networks Learning
nnCostFunction 消耗公式: a1 = [ones(m,) X]; z2 = a1*Theta1'; pre = sigmoid(a1*Theta1'); a2 = [ones(m,) p ...
- 【比赛】NOIP2017 总结
一.比赛过程 Day1: 拿到题目后,立即把所有题目都看了一遍,发现没有很虚的期望DP和概率DP,感到很庆幸.然后发现今年的题目顺序好像有点不对,T1是数论,T2像是模拟,这难道是把两天的基础题放到一 ...
- RocketMQ生产者消息篇
系列文章 RocketMQ入门篇 RocketMQ生产者流程篇 RocketMQ生产者消息篇 前言 上文RocketMQ生产者流程篇中详细介绍了生产者发送消息的流程,本文将重点介绍发送消息的通信模式以 ...
- struts2 的自定义 拦截器
Struts2的 拦截器: 对于拦截器,Struts2官方给出的 定义是: 拦截器是动态拦截Action调用的对象.它提供了一种机制,使开发者可以定义一段代码,在Action执行之前或者之后被调用执行 ...
- [SCOI2016] 背单词 (Trie树)
$pdf\space solution$ link #include<iostream> #include<algorithm> #include<cstrin ...
- 关于nodejs的几个干货(读中文文件编码问题/发送邮件/定时任务)
关于nodejs读取中文文件真是折腾了不少时间,网上各种方案,最后没有一个适用我,好在解决了. 下面的三个知识点都是从项目中抽出的,要单独运行脚本的话需要用全局模式来安装模块,比如安装中文转换模块(后 ...
- javascript实现div的显示和隐藏
http://www.cnblogs.com/oec2003/archive/2007/05/05/736492.html <html> <head> <meta htt ...