在线LCA一般大家都会用倍增吧,时间复杂度O(nlogn),空间复杂度O(nlogn),都是非常严格的复杂度限制,并且各种边界处理比较麻烦,有没有更快更好的办法呢?

我们发现,在树链剖分时,我们不经意的找到了LCA,能不能用这种方法找LCA呢?

答案是肯定的,使用轻重链剖分达到的LCA,时间复杂度最坏为O(logn),预处理是O(n)的dfs,比起每次处理严格O(nlogn),预处理O(nlogn)的倍增看起来好了很多,下面我们就用实验测量一下。

使用一个随机数据生成器生成了99组100000个点100000次询问的LCA,测试结果如下:

测试环境:intel I5-4200M 2.5GHz*2 windows7 VMware虚拟机

测试软件:cena 0.8

测试结果:

可以看到,树链剖分的代码比倍增有明显的优势,但是优势并不是特别大,平均每个点快了0.1秒左右。没有快太多的原因还是因为常数较大,劣处是代码量大了大约三十行。事实上,本人认为树链剖分比较好想,边界容易。

代码:

倍增:by Ommy_Zhang

 #include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAXN 101010
#define MAXM 202020
#define TC 2000000
int n,m,u,v,k,lca,lastans;
int head[MAXN],next[MAXM],go[MAXM],cnt;
int father[MAXN][],deep[MAXN]; void add(int a,int b)
{
go[++cnt]=b;
next[cnt]=head[a];
head[a]=cnt;
}
void dfs(int x)
{
for(int k=;father[x][k];++k)
father[x][k+]=father[ father[x][k] ][k];
for(int e=head[x];e;e=next[e])
if(go[e]!=father[x][])
{
deep[go[e]]=deep[x]+;
father[go[e]][]=x;
dfs(go[e]);
}
}
int get_lca(int a,int b)
{
if(deep[a] < deep[b])
{
int t=a;
a=b;
b=t;
}
int d=deep[a]-deep[b];
for(int k=;k<;++k)
if((d>>k)&)
a=father[a][k];
if(a==b) return a; for(int k=;k>=;--k)
if(father[a][k]!=father[b][k])
{
a=father[a][k];
b=father[b][k];
}
return father[a][]; }
int main()
{
freopen ("LCA.in","r",stdin);
freopen ("LCA.out","w",stdout);
int n;
scanf("%d",&n);
int j,k;
for (int i=;i<n;++i)
{
scanf("%d%d",&j,&k);
add(j,k);
add(k,j);
}
dfs();
int m;
scanf("%d",&m);
for (int i=;i<=m;++i)
{
scanf("%d%d",&j,&k);
printf("%d\n",get_lca(j,k));
}
return ;
}

树链剖分:by SymenYang

#include <iostream>
#include <cstdio>
#include <algorithm>
#define maxn 100010
using namespace std;
struct edge
{
int to;
edge* next;
}ed[]; edge* head[];
int cnt=-;
void add(int j,int k)
{
edge* q=&ed[++cnt];
q->to=k;
q->next=head[j];
head[j]=q;
}
int fa[maxn];
int top[maxn];
int dep[maxn];
edge* wei[maxn];
int size[maxn];
void dfs(int now,int de,int last)
{
dep[now]=de;
size[now]=;
fa[now]=last;
int maxx=;
for (edge* q=head[now];q!=NULL;q=q->next)
{
if (q->to!=last)
{
dfs(q->to,de+,now);
if (size[q->to]>maxx)
{
wei[now]=q;
}
size[now]+=size[q->to];
}
}
return;
} void dfs2(int now,int last,int to)
{
top[now]=to;
if (wei[now])
dfs2(wei[now]->to,now,to);
for (edge* q=head[now];q!=NULL;q=q->next)
{
if (q->to!=last&&q!=wei[now])
{
dfs2(q->to,now,q->to);
}
}
return;
} int get_lca(int a,int b)
{
while (top[a]!=top[b])
{
if (dep[top[a]]<dep[top[b]]) a^=b^=a^=b;
a=fa[top[a]];
}
return dep[a]<dep[b]? a:b;
} int main()
{
freopen ("LCA.in","r",stdin);
freopen ("LCA.out","w",stdout);
int n;
scanf("%d",&n);
int j,k;
for (int i=;i<=n;++i) head[i]=NULL;
for (int i=;i<n;++i)
{
scanf("%d%d",&j,&k);
add(j,k);
add(k,j);
}
dfs(,,);
dfs2(,,);
int m;
scanf("%d",&m);
for (int i=;i<=m;++i)
{
scanf("%d%d",&j,&k);
printf("%d\n",get_lca(j,k));
}
return ;
}

每日算法——新型在线LCA的更多相关文章

  1. hdu3078 建层次树+在线LCA算法+排序

    题意:n个点,n-1条边构成无向树,每个节点有权,Q次询问,每次或问从a->b的最短路中,权第k大的值,/或者更新节点a的权, 思路:在线LCA,先dfs生成树0,标记出层数和fa[](每个节点 ...

  2. 在线LCA模板

    在线LCA 如求A,B两点的LCA,先计算出各个结点的深度d[],然后,通过递推公式求出各个结点的2次方倍的祖先p[],假设d[A] > d[B],则找到d[p[A][i]] == d[B]也就 ...

  3. hdu_4547_CD操作(在线LCA)

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=4547 题意:中文,不解释 题解:很裸的LCA,注意父目录打开子目录一次就够了,这里我才用倍增在线LCA ...

  4. 每日算法 - day 15

    每日算法 those times when you get up early and you work hard; those times when you stay up late and you ...

  5. Tarjan算法离线 求 LCA(最近公共祖先)

    本文是网络资料整理或部分转载或部分原创,参考文章如下: https://www.cnblogs.com/JVxie/p/4854719.html http://blog.csdn.net/ywcpig ...

  6. POJ 1330 Nearest Common Ancestors (LCA,倍增算法,在线算法)

    /* *********************************************** Author :kuangbin Created Time :2013-9-5 9:45:17 F ...

  7. ST(RMQ)算法(在线)求LCA

    在此之前,我写过另一篇博客,是倍增(在线)求LCA.有兴趣的同学可以去看一看.概念以及各种暴力就不在这里说了,那篇博客已经有介绍了. 不会ST算法的同学点这里 ST(RMQ)算法在线求LCA 这个算法 ...

  8. 【算法】RMQ LCA 讲课杂记

    4月4日,应学弟要求去了次学校给小同学们讲了一堂课,其实讲的挺内容挺杂的,但是目的是引出LCA算法. 现在整理一下当天讲课的主要内容: 开始并没有直接引出LCA问题,而是讲了RMQ(Range Min ...

  9. 利用Tarjan算法解决(LCA)二叉搜索树的最近公共祖先问题——数据结构

    相关知识:(来自百度百科)  LCA(Least Common Ancestors) 即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先. 例如: 1和7的最近公共祖先为5: 1和5的 ...

随机推荐

  1. Math.floor() 与 parseInt()

    parseInt()与Math.floor()都能实现数字的向下取整,但是两者存在根本上的差异,1.Math.floor()用于一个数的向下取整,不能解析字符串 <script type=&qu ...

  2. 【剑指Offer】剑指offer题目汇总

      本文为<剑指Offer>刷题笔记的总结篇,花了两个多月的时间,将牛客网上<剑指Offer>的66道题刷了一遍,以博客的形式整理了一遍,这66道题属于相对基础的算法题目,对于 ...

  3. Luogu P1892 [BOI2003]团伙

    P1892 [BOI2003]团伙 题目描述 1920年的芝加哥,出现了一群强盗.如果两个强盗遇上了,那么他们要么是朋友,要么是敌人.而且有一点是肯定的,就是: 我朋友的朋友是我的朋友: 我敌人的敌人 ...

  4. THUSC2019 退役记

    Day -inf 这一个半月潜心搞文化课,把文化课的坑填上了不少,我文化课的底子真是薄啊 一年前没想过我还挺有希望进队的,最后还差点冲上 一年后说不定会发现我搞文化课也能搞得不错呢? 一切都是未知 t ...

  5. 面试:A

    分析 System.Collections.Generic.List<T> 的 Remove<T> 方法和 Clear 方法的实现细节(不允许使用“移除”“清除”这种概念模糊的 ...

  6. R 安装car包失败

    在RStudio里安装car包的时候报错 /usr/bin/ld: cannot find -llapack /usr/bin/ld: cannot find -lblas make: *** [qu ...

  7. 玩转vim编辑器

    1.vim 编辑器可以自定义配置:包含初始化命令的文件叫vimrc(h vimrc),version ---查看版本号.系统-用户配置文件所在位置. 2. 可视模式: 操作一块区域代码: 按v    ...

  8. STM32学习笔记:读写内部Flash(介绍+附代码)

    一.介绍 首先我们需要了解一个内存映射: stm32的flash地址起始于0x0800 0000,结束地址是0x0800 0000加上芯片实际的flash大小,不同的芯片flash大小不同. RAM起 ...

  9. PAT 1119 Pre- and Post-order Traversals

    Suppose that all the keys in a binary tree are distinct positive integers. A unique binary tree can ...

  10. 一个电商项目的Web服务化改造4:方案和架构,通用接口的定义和实现

        最近一直在做一个电商项目,需要把原有单系统架构的项目,改造成基于服务的架构,SOA.     有点挑战,做完了,会有很大进步. 上一篇,我们明确了我们的"规范和约定". 从 ...