在线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. 微智魔盒APP开发程序解析

    微智魔盒系统开发找崔经理l88Z.6ZZ685l.微智魔盒app开发.微智魔盒商城开发.微智魔盒软件开发,微智魔盒模式开发,微智魔盒源码开发.微智魔盒开发. @Override publicvoidr ...

  2. Oracle,sqlserver,mySQl的区别和联系:

    1.日期处理方式 2.对保留字和关键字的处理方式: Oracle,sqlserver,mySQl的保留字不可以用作列字段,关键字可以,但他们对关键字的处理方式又不同: Oracle:关键字作为列时:用 ...

  3. python numpy array 与matrix 乘方

    python numpy array 与matrix 乘方 编程语言 waitig 1年前 (2017-04-18) 1272℃ 百度已收录 0评论 数组array 的乘方(**为乘方运算符)是每个元 ...

  4. Highcharts教程--把js代码从html中抽离出来,放到单独的一个js文件中。由html页面调用

    1.html页面写法 <!DOCTYPE html> <html lang="en"> <head> <meta charset=&quo ...

  5. Linux - redis-cluster搭建

    目录 Linux - redis-cluster搭建 Linux - redis-cluster搭建 1.准备6个数据库节点,也就是6个redis实例,也就是6个配置文件 配置文件如下 redis-7 ...

  6. 洛谷 2234 BZOJ 1588 HNOI2002 营业额统计

    [题解] treap模板题,直接用Treap维护前驱.后继,每次找到更接近当前val的加上就好了. #include<cstdio> #include<algorithm> # ...

  7. js调用ro的webservice

    Enabling JavaScript Access on the Server Drop the JavaScriptHttpDispatcher component onto the server ...

  8. XOR Queries

    XOR Queries 时间限制: 1000ms   内存限制: 256M 描述 给出一个长度为n的数组C,回答m个形式为(L,R,A,B)的询问,含义为存在多少个不同的数组下标k∈[L,R]满足C[ ...

  9. A - Number Sequence

    Given two sequences of numbers : a11, a22, ...... , aNN, and b11, b22, ...... , bMM(1 <= M <= ...

  10. Hilbert曲线简单介绍及生成算法

    Hilbert曲线 Hilbert曲线是一种填充曲线,相似的填充曲线还包含Z曲线.格雷码等其它方法.Hilbert曲线根据自身空间填充曲线的特性,能够线性地贯穿二维或者更高维度每一个离散单元.而且只穿 ...