在线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. CAD在网页中得到批注信息

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 3 ...

  2. javaWEB中web.xml配置文件相关

    1.常用节点的执行顺序: context-param -> listenter -> filter -> servlet -> interceptor,其中有多个filter的 ...

  3. div+css 组织结构

    <!DOCTYPE html><html><head> <meta charset="utf-8"> <title>家谱 ...

  4. 基于Arduino的音乐动感节奏灯

    1.音乐动感节奏灯是个什么东西? 前段时间听音乐觉得无聊,便想着音乐光听也没意思啊,能不能 “看见” 音乐呢?于是谷歌了一番,发现还真有人做了将音乐可视化的东西,那就是音乐节奏灯.说的简单点就是LED ...

  5. PAT 1110 Complete Binary Tree

    Given a tree, you are supposed to tell if it is a complete binary tree. Input Specification: Each in ...

  6. H5音乐播放器

    前段时间无聊用JavaScript基于H5的audio写一个音乐播放器.误喷,技术有限,文笔不好之处希望各位大神海涵. 1.HTML代码: <div id="music" c ...

  7. qwb和李主席

    qwb和李主席 Time Limit: 4 Sec  Memory Limit: 128 MB Description qwb和李主席打算平分一堆宝藏,他们想确保分配公平,可惜他们都太懒了,你能帮助他 ...

  8. ZOJ - 2243 - Binary Search Heap Construction

    先上题目: Binary Search Heap Construction Time Limit: 5 Seconds      Memory Limit: 32768 KB Read the sta ...

  9. Performance Metrics(性能指标1)

    Performance Metrics(性能指标) 在我们开始旅行本书之前,我必须先了解本书的性能指标和希望优化后的结果,在第二章中,我们探索更多的性能检测工具和性能指标,可是,您得会使用这些工具和明 ...

  10. 固定一个div在浏览器底部

    转自原文 如何固定一个div在浏览器底部   方法1:使用CSS绝对定位 div{ position:absolute; bottom:0px; left:0px; } 方法2:使用CSS固定定位 d ...