----代码都是  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. pyqt5 eric6

    1 安装Anaconda3 2 python环境变量改为Anaconda3中python 3 pip安装pyqt5 ,pip安装pyqt5-tool 其中tool中包含eric6 ui文件必须使用的d ...

  2. Ubuntu安装使用中的一些注意事项

    在win7上安装VMware workstations10.0 ,在VMware workstations10.0上安装Ubuntu14.04 64位时,关于网络的连接注意: win7 网络连接里上的 ...

  3. DataRow数组根据指定列排序

    正序:DataRow[] datarow = datarow.OrderBy(x=>x["Ybrq"]).ToArray(); 倒序:DataRow[] datarow = ...

  4. C#全局钩子和局部钩子记录

    源自:https://blog.csdn.net/programvae/article/details/80292076 最近碰巧要使用键盘钩子,于是在网上搜索了一番,发现大多数博客的文章都是雷同的, ...

  5. File FileStream StreamReader StreamWriter C#

    存在各种各样的IO设备,比如说文件File类(字符串文件和二进制文件),可以直接使用File类对文件进行读写操作. 这些各种IO的读取和写入是通过流的形式实现的,基类为Stream,针对各种不同的IO ...

  6. Java并发编程之线程安全、线程通信

    Java多线程开发中最重要的一点就是线程安全的实现了.所谓Java线程安全,可以简单理解为当多个线程访问同一个共享资源时产生的数据不一致问题.为此,Java提供了一系列方法来解决线程安全问题. syn ...

  7. 解决MySQL Slave 触发 oom-killer

    最近经常有收到MySQL实例类似内存不足的报警信息,登陆到服务器上一看发现MySQL 吃掉了99%的内存,God ! 有时候没有及时处理,内核就会自己帮我们重启下MySQL,然后我们就可以看到 dme ...

  8. D-Separation(D分离)-PRML-8.22-Graphical Model 五 18 by 小军

    D-Separation(D分离)-PRML-8.22-Graphical Model 五18by 小军   一.引言 在贝叶斯网络的学习过程中,经常会遇到(D-Separation)D-分离这个概念 ...

  9. [USACO12NOV]同时平衡线Concurrently Balanced Strings DP map 思维

    题面 [USACO12NOV]同时平衡线Concurrently Balanced Strings 题解 考虑DP. \(f[i]\)表示以\(i\)为左端点的合法区间个数.令\(pos[i]\)表示 ...

  10. [BZOJ1500][NOI2005]维修数列 解题报告 Splay

    Portal Gun:[BZOJ1500][NOI2005]维修数列 有一段时间没写博客了,最近在刚数据结构......各种板子背得简直要起飞,题目也是一大堆做不完,这里就挑一道平衡树的题来写写好了 ...