每日算法——新型在线LCA
在线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的更多相关文章
- hdu3078 建层次树+在线LCA算法+排序
题意:n个点,n-1条边构成无向树,每个节点有权,Q次询问,每次或问从a->b的最短路中,权第k大的值,/或者更新节点a的权, 思路:在线LCA,先dfs生成树0,标记出层数和fa[](每个节点 ...
- 在线LCA模板
在线LCA 如求A,B两点的LCA,先计算出各个结点的深度d[],然后,通过递推公式求出各个结点的2次方倍的祖先p[],假设d[A] > d[B],则找到d[p[A][i]] == d[B]也就 ...
- hdu_4547_CD操作(在线LCA)
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=4547 题意:中文,不解释 题解:很裸的LCA,注意父目录打开子目录一次就够了,这里我才用倍增在线LCA ...
- 每日算法 - day 15
每日算法 those times when you get up early and you work hard; those times when you stay up late and you ...
- Tarjan算法离线 求 LCA(最近公共祖先)
本文是网络资料整理或部分转载或部分原创,参考文章如下: https://www.cnblogs.com/JVxie/p/4854719.html http://blog.csdn.net/ywcpig ...
- POJ 1330 Nearest Common Ancestors (LCA,倍增算法,在线算法)
/* *********************************************** Author :kuangbin Created Time :2013-9-5 9:45:17 F ...
- ST(RMQ)算法(在线)求LCA
在此之前,我写过另一篇博客,是倍增(在线)求LCA.有兴趣的同学可以去看一看.概念以及各种暴力就不在这里说了,那篇博客已经有介绍了. 不会ST算法的同学点这里 ST(RMQ)算法在线求LCA 这个算法 ...
- 【算法】RMQ LCA 讲课杂记
4月4日,应学弟要求去了次学校给小同学们讲了一堂课,其实讲的挺内容挺杂的,但是目的是引出LCA算法. 现在整理一下当天讲课的主要内容: 开始并没有直接引出LCA问题,而是讲了RMQ(Range Min ...
- 利用Tarjan算法解决(LCA)二叉搜索树的最近公共祖先问题——数据结构
相关知识:(来自百度百科) LCA(Least Common Ancestors) 即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先. 例如: 1和7的最近公共祖先为5: 1和5的 ...
随机推荐
- centOS Linux下用yum安装mysql
centOS Linux下用yum安装mysql 第一篇:安装和配置MySQL 第一步:安装MySQL [root@192 local]# yum -y install mysql- ...
- Oracle,sqlserver,mySQl的区别和联系:
1.日期处理方式 2.对保留字和关键字的处理方式: Oracle,sqlserver,mySQl的保留字不可以用作列字段,关键字可以,但他们对关键字的处理方式又不同: Oracle:关键字作为列时:用 ...
- 2018.03.04 晚上Atcoder比赛
C - March Time limit : 2sec / Memory limit : 256MB Score : 300 points Problem Statement There are N ...
- Fang Fang HDU - 5455 (思维题)
Fang Fang says she wants to be remembered. I promise her. We define the sequence FF of strings. F0 = ...
- 51nod1103 N的倍数
[题解] 先预处理出模N意义下的前缀和sum[i]. 1.如果sum[i]=0,那么1~i的数之和就是N的倍数 2.sum[i]%N总共有0~N-1这N种情况:根据1,如果sum[i]为0则必定有解: ...
- python基础综合题----选自python二级考试
<笑傲江湖>是金庸的重要武侠作品之一.这里给出一个<笑傲江湖>的网络版本, 文件名为“笑傲江湖-网络版.txt”. ...
- JavaSE 学习笔记之Object对象(八)
Object:所有类的直接或者间接父类,Java认为所有的对象都具备一些基本的共性内容,这些内容可以不断的向上抽取,最终就抽取到了一个最顶层的类中的,该类中定义的就是所有对象都具备的功能. 具体方法: ...
- Vue2构建项目实战
转载整理自http://blog.csdn.net/fungleo/article/details/77575077 vue构建单页应用原理 SPA 不是指水疗.是 single page web a ...
- Linux - Virsh
virsh命令 suspend resume dumpxml KVM平台以存储池的形式对存储进行统一管理,所谓存储池能够理解为本地文件夹.通过远端磁盘阵列(iSCSI.NFS)分配过来磁盘或文件夹 ...
- CF #321 (Div. 2) E
用线段树维护哈希,类似于进位制的一个哈希 a[i]*p^i+a[i-1]*p^i-1... 然后,线段树存在某区间的哈希的值,对于更新,则只需提前计算出整段的哈希值即可. 判断是否相等,由于相隔为d, ...