----代码都是  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. poj 3254(状态压缩DP)

    poj  3254(状态压缩DP) 题意:一个矩阵里有很多格子,每个格子有两种状态,可以放牧和不可以放牧,可以放牧用1表示,否则用0表示,在这块牧场放牛,要求两个相邻的方格不能同时放牛,即牛与牛不能相 ...

  2. Centos/Fedora下安装Twisted,failed with error code 1 in /tmp/pip-build-H1bj8E/twisted/解决方法

    Python踩坑之路 pip/easy_install无法安装Twisted或者安装后无法导入Twisted 看到MM网站上很多图,想用Scrapy框架爬点图,遇到各种库的问题,蛋疼. 一直twist ...

  3. eclipse 导入 gradle 项目遇到 UnsupportedConfigurationException 异常

    异常描述: org.eclipse.buildship.core.UnsupportedConfigurationException: Project at 'D:\XXXX_workspace\XX ...

  4. POJ2699_The Maximum Number of Strong Kings

    这题目,,,真是...诶.坑了好久. 给一个有向图.U->V表示U可以打败V并得一分. 如果一个人的得分最高,或者他打败所有比自己得分高的人,那么此人就是king. 现在给出每个人的得分,求最多 ...

  5. BZOJ5294 BJOI2018二进制(线段树)

    二进制数能被3整除相当于奇数.偶数位上1的个数模3同余.那么如果有偶数个1,一定存在重排方案使其合法:否则则要求至少有两个0且至少有3个1,这样可以给奇数位单独安排3个1. 考虑线段树维护区间内的一堆 ...

  6. c语言基本数据类型(short、int、long、char、float、double)

    一 C 语言包含的数据类型 short.int.long.char.float.double 这六个关键字代表C 语言里的六种基本数据类型. 在不同的系统上,这些类型占据的字节长度是不同的: 在32 ...

  7. 学习Spring Boot:(四)应用日志

    前言 应用日志是一个系统非常重要的一部分,后来不管是开发还是线上,日志都起到至关重要的作用.这次使用的是 Logback 日志框架. 正文 Spring Boot在所有内部日志中使用Commons L ...

  8. Alpha 冲刺 —— 十分之六

    队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭鸭鸭鸭鸭鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作 测试服务器并行能力 学习MSI.CUDA ...

  9. 用Python实现的数据结构与算法:快速排序

    一.概述 快速排序(quick sort)是一种分治排序算法.该算法首先 选取 一个划分元素(partition element,有时又称为pivot):接着重排列表将其 划分 为三个部分:left( ...

  10. adb server version (32) doesn't match this client (36); killing...

    http://blog.csdn.net/seaker_/article/details/55107598 FAQ: adb server version (36) doesn't match thi ...