----代码都是  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的更多相关文章

  1. 倍增\ tarjan求lca

    对于每个节点v,记录anc[v][k],表示从它向上走2k步后到达的节点(如果越过了根节点,那么anc[v][k]就是根节点). dfs函数对树进行的dfs,先求出anc[v][0],再利用anc[v ...

  2. 图论分支-倍增Tarjan求LCA

    LCA,最近公共祖先,这是树上最常用的算法之一,因为它可以求距离,也可以求路径等等 LCA有两种写法,一种是倍增思想,另一种是Tarjan求法,我们可以通过一道题来看一看, 题目描述 欢乐岛上有个非常 ...

  3. Tarjan求LCA

    LCA问题算是一类比较经典的树上的问题 做法比较多样 比如说暴力啊,倍增啊等等 今天在这里给大家讲一下tarjan算法! tarjan求LCA是一种稳定高速的算法 时间复杂度能做到预处理O(n + m ...

  4. 详解使用 Tarjan 求 LCA 问题(图解)

    LCA问题有多种求法,例如倍增,Tarjan. 本篇博文讲解如何使用Tarjan求LCA. 如果你还不知道什么是LCA,没关系,本文会详细解释. 在本文中,因为我懒为方便理解,使用二叉树进行示范. L ...

  5. tarjan求lca的神奇

    题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...

  6. 【Tarjan】洛谷P3379 Tarjan求LCA

    题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...

  7. HDU 2586 倍增法求lca

    How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  8. 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 ...

  9. 倍增法求LCA

    倍增法求LCA LCA(Least Common Ancestors)的意思是最近公共祖先,即在一棵树中,找出两节点最近的公共祖先. 倍增法是通过一个数组来实现直接找到一个节点的某个祖先,这样我们就可 ...

随机推荐

  1. PHP 常用函数总结(一)

    重点: 看函数的 ‘参数’ 和 ‘返回值’ 文档:http://www.w3school.com.cn/php/php_ref_array.asp http://www.w3school.com.cn ...

  2. Android Holo Theme的三种表现形式

    摘录自:http://blog.csdn.net/xyz_lmn/article/details/12000941 Holo Theme的三种表现形式 Holo Theme是android4.0开始提 ...

  3. variant conversion error for variable v23

    excel数据导入到oracle数据库出现的问题 V23指的是excel列.,这列的数据长度超出或者类型与数据库表不一致导致的 解决方法,1.清空该列,再建个新列 2.用access  SQL查出长度 ...

  4. 消除unchecked cast Warning

    在Java中,经常会将一个Object类型转成自己想要的Map.List等等.通常的做法是: Object obj = ....; Map<String, String> castMap ...

  5. codevs1839洞穴勘测

    题目链接:http://codevs.cn/problem/1839/ 题目描述 Description 辉辉热衷于洞穴勘测.某天,他按照地图来到了一片被标记为JSZX的洞穴群地区.经过初步勘测,辉辉 ...

  6. kafka问题集(二):__consumer_offsets topic的分区中有一个分区数据很多,多达1T

    仅个人实践中所遇到的问题,若有不对的,欢迎交流! 一.场景描述 kafka集群中有几台突然挂了,后台日志显示设备空间满了,消息无法写入__consumer_offsets topic的分区中了.查看k ...

  7. loj2542 「PKUWC2018」随机游走 【树形dp + 状压dp + 数学】

    题目链接 loj2542 题解 设\(f[i][S]\)表示从\(i\)节点出发,走完\(S\)集合中的点的期望步数 记\(de[i]\)为\(i\)的度数,\(E\)为边集,我们很容易写出状态转移方 ...

  8. 洛谷 P1972 [SDOI2009]HH的项链 解题报告

    P1972 [SDOI2009]HH的项链 题目描述 HH 有一串由各种漂亮的贝壳组成的项链.HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义.HH 不断 ...

  9. 【bzoj3527】 Zjoi2014—力

    http://www.lydsy.com/JudgeOnline/problem.php?id=3527 (题目链接) 题意 $${F_i=\sum_{j<i} {\frac{q_iq_j}{( ...

  10. java多线程 -- 创建线程的第三者方式 实现Callable接口

    Java 5.0 在 java.util.concurrent 提供了一个新的创建执行线程的方式:Callable 接口Callable 接口类似于 Runnable,两者都是为那些其实例可能被另一个 ...