BZOJ1602

求最近公共祖先有三种常用的方法,在线的有两种,分别是树上倍增算法和转化为RMQ问题

离线的有一种,使用Tarjan算法

这里,我们介绍复杂度优异并且在线的倍增算法,至于后续的两种方法等到之后接触了相关方面的内容之后再进行补充,到时候写一篇总结

我们在计算树上的两点的最短路径时,如果按照图的节奏去求,那势必是会超时的,树有着自己优异的性质,那就是十分适合递归

下面先给出计算树上两点最短路距离的公式:

dis[x]表示根到x的距离
则x,y距离为dis[x]+dis[y]-*dis[lca(x,y)]

理解起来还是很容易的,下面以BZOJ1602为例来介绍一下实现的方法:

int n,q,cnt;
bool vis[maxn];
int head[maxn],deep[maxn],dis[maxn],fa[maxn][];
struct data{int to,next,v;}e[*maxn];

直接用邻接表来存树,然后这里的vis是协同dfs预处理来判重的

deep是每一个节点的深度,dis是这个节点到根节点的距离,fa[x][y]表示x往上倒2^y的祖先是谁,y=0是就是它爹

data不再赘述,邻接表实现不再赘述

void dfs(int x)
{
vis[x]=;
for(int i=;i<=;i++)
{
if(deep[x]<(<<i)) break;
fa[x][i]=fa[fa[x][i-]][i-];
}
for(int i=head[x];i;i=e[i].next)
{
if(vis[e[i].to]) continue;
deep[e[i].to]=deep[x]+;
dis[e[i].to]=dis[x]+e[i].v;
fa[e[i].to][]=x;
dfs(e[i].to);
}
}

dfs预处理出fa数组,deep数组和vis数组,这是解决很多树问题的一个前置基础

然后就是倍增算法:

int lca(int x,int y)
{
if(deep[x]<deep[y]) swap(x,y);
int d=deep[x]-deep[y];
for(int i=;i<=;i++)
if((<<i)&d) x=fa[x][i];
for(int i=;i>=;i--)
if(fa[x][i]!=fa[y][i])
{x=fa[x][i];y=fa[y][i];}
if(x==y) return x;
else return fa[x][];
}

根据两个节点的的深度,如不同,向上调整深度大的节点,使得两个节点在同一层上,如果正好是祖先结束,否则,将两个节点同时上移,查询最近公共祖先

其实这里所有的实现细节之后都应该自己在纸上画一画熟悉熟悉

最后给出完整的实现:

 #include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=;
int n,q,cnt;
bool vis[maxn];
int head[maxn],deep[maxn],dis[maxn],fa[maxn][];
struct data{int to,next,v;}e[*maxn];
void ins(int u,int v,int w)
{e[++cnt].to=v;e[cnt].next=head[u];e[cnt].v=w;head[u]=cnt;}
void insert(int u,int v,int w)
{ins(u,v,w);ins(v,u,w);}
void dfs(int x)
{
vis[x]=;
for(int i=;i<=;i++)
{
if(deep[x]<(<<i)) break;
fa[x][i]=fa[fa[x][i-]][i-];
}
for(int i=head[x];i;i=e[i].next)
{
if(vis[e[i].to]) continue;
deep[e[i].to]=deep[x]+;
dis[e[i].to]=dis[x]+e[i].v;
fa[e[i].to][]=x;
dfs(e[i].to);
}
}
int lca(int x,int y)
{
if(deep[x]<deep[y]) swap(x,y);
int d=deep[x]-deep[y];
for(int i=;i<=;i++)
if((<<i)&d) x=fa[x][i];
for(int i=;i>=;i--)
if(fa[x][i]!=fa[y][i])
{x=fa[x][i];y=fa[y][i];}
if(x==y) return x;
else return fa[x][];
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
insert(u,v,w);
}
dfs();
for(int i=;i<=q;i++)
{
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",dis[x]+dis[y]-*dis[lca(x,y)]);
}
return ;
}

图论:LCA-树上倍增的更多相关文章

  1. Codevs 2370 小机房的树 LCA 树上倍增

    题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天,他们想爬到一个节点上去搞基,但是作为两只虫子, ...

  2. HDU 4822 Tri-war(LCA树上倍增)(2013 Asia Regional Changchun)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4822 Problem Description Three countries, Red, Yellow ...

  3. LCA树上倍增

    LCA就是最近公共祖先,比如 节点10和11的LCA就是8,9和3的LCA就是3. 我们这里讲一下用树上倍增来求LCA. 大家都可以写出暴力解法,两个节点依次一步一步往上爬,直到爬到了相同的一个节点. ...

  4. 关于树论【LCA树上倍增算法】

    补了一发LCA,表示这东西表面上好像简单,但是细节真挺多. 我学的是树上倍增,倍增思想很有趣~~(爸爸的爸爸叫奶奶.偶不,爷爷)有一个跟st表非常类似的东西,f[i][j]表示j的第2^i的祖先,就是 ...

  5. LCA——树上倍增

    首先,什么是LCA? LCA:最近公共祖先 祖先:从当前点到根节点所经过的点,包括他自己,都是这个点的祖先 A和B的公共祖先:同时是A,B两点的祖先的点 A和B的最近公共祖先:深度最大的A和B的公共祖 ...

  6. 洛谷P3379lca,HDU2586,洛谷P1967货车运输,倍增lca,树上倍增

    倍增lca板子洛谷P3379 #include<cstdio> struct E { int to,next; }e[]; ],anc[][],log2n,deep[],n,m,s,ne; ...

  7. LCA树上倍增求法

    1.LCA LCA就是最近公共祖先(Least common ancestor),x,y的LCA记为z=LCA(x,y),满足z是x,y的公共祖先中深度最大的那一个(即离他们最近的那一个)qwq 2. ...

  8. NOIP2013 货车运输 (最大生成树+树上倍增LCA)

    死磕一道题,中间发现倍增还是掌握的不熟 ,而且深刻理解:SB错误毁一生,憋了近2个小时才调对,不过还好一遍AC省了更多的事,不然我一定会疯掉的... 3287 货车运输 2013年NOIP全国联赛提高 ...

  9. 树上倍增求LCA及例题

    先瞎扯几句 树上倍增的经典应用是求两个节点的LCA 当然它的作用不仅限于求LCA,还可以维护节点的很多信息 求LCA的方法除了倍增之外,还有树链剖分.离线tarjan ,这两种日后再讲(众人:其实是你 ...

  10. 两种lca的求法:树上倍增,tarjan

    第一种:树上倍增 f[x,k]表示x的2^k辈祖先,即x向根结点走2^k步达到的结点. 初始条件:f[x][0]=fa[x] 递推式:f[x][k]=f[ f[x][k-1] ][k-1] 一次bfs ...

随机推荐

  1. window.open()与window.showModalDialog区别

    window.open()与window.showModalDialog区别 弹出窗口两种方式:    1.window.showModalDialog:      var feature = &qu ...

  2. Java学习个人备忘录之面向对象概念

    对象,其实就是该类事物实实在在存在的个体. 类与对象之间的关系?类:一类事物的描述.对象:该类事物的实例.在java中通过new来创建的.举例来说,类就是汽车说明书,类只能在理论上造一辆汽车,并且这个 ...

  3. QWidget一生,从创建到销毁事件流

    版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:QWidget一生,从创建到销毁事件流     本文地址:http://techieliang ...

  4. 实验吧编程题:Hashkill

    原题:6ac66ed89ef9654cf25eb88c21f4ecd0是flag的MD5码,(格式为ctf{XXX_XXXXXXXXXXX_XXXXX})由一个0-1000的数字,下划线,纽约的一个区 ...

  5. Git命令基本操作

    本文从以下九个方面,介绍Git命令的基本操作: 一. Git安装 二. Git基本配置 三. 创建Git仓库 四. 获得Git仓库 五. 提交更新 六. 提交历史查看 七. 远程仓库 八. 打Tags ...

  6. 编译android6.0错误recipe for target 'out/host/linux-x86/obj/lib/libart.so' failed

    转自:http://blog.csdn.net/ztguang/article/details/52856076 trip: libpagemap_32 (out/target/product/xx/ ...

  7. Flink的序列化与flink-hadoop-compatibility

    最近 用户提交了一个问题 说他的jar包里明明包含相关的类型 但是在提交Flink作业的时候 却报出classnotfound的错误 查看之后发现 这里是flink的一个没有说的太明白的地方 用户的代 ...

  8. Python 配置日志的几种方式

    Python配置日志的几种方式 作为开发者,我们可以通过以下3种方式来配置logging: (1)使用Python代码显式的创建loggers,handlers和formatters并分别调用它们的配 ...

  9. (转)如何用U盘创建Linux系统盘

    (转)http://teliute.org/linux/TeUbt/lesson60/lesson60.html 创建一个U盘linux安装盘,用以启动系统并安装: 1.启动盘创建器 1)点击主按钮, ...

  10. [luoguT30208]太极剑

    题面在这里 description 在一个圆环上给出\(n\)条端点在圆环上的绳子, 每次在圆环上切割的轨迹是一条直线,可以将可以将所有与这条直线相交的绳子切断. 求切割次数的最小值. data ra ...