LCA(Least Common Ancestors),即最近公共祖先,是指这样一个问题:在有根树中,找出某两个结点u和v最近的公共祖先(另一种说法,离树根最远的公共祖先)。

  知识需求:1)RMQ的ST算法   2)欧拉序列

1)RMQ的ST算法:

  可以参考我的这篇博客:RMQ原理及实现

2)欧拉序列:

  所谓欧拉序,就是从根结点出发,按dfs的顺序经过每一个结点最后绕回原点的顺序,比如下面这个例子,欧拉序就是A-B-D-B-E-G-E-B-A-C-F-H-F-C-A

  那么欧拉序和rmq与LCA有什么关系呢,首先我们知道RMQ可以方便的在线求出区间最小值,以求上图中DG两点最近公共祖先为例,我们先处理出他的欧拉序,我们记录下每个结点第一次被访问的时间,以及每个时间访问的结点编号与结点深度,这时,我们不难发现,D与G第一次出现的时间之间的区域深度最小值就是这两个点对应的最近公共祖先B的深度,我们修改rmq,让其不再返回最小深度,而是返回区间最小深度对应的下标,这里就是求欧拉序中的访问时间,有了这个时间,加上之前的记录,我们可以直接得出该点的编号,从而求出最近公共祖先。

练习题:题目链接

练习题AC代码:

 #include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <set>
#include <queue>
#include <map> using namespace std; const int MAXN = * ; int rmq[MAXN * ]; //节点深度序列 struct ST {
int mm[MAXN * ];
int dp[MAXN][];
void init(int n) {
mm[] = -;
for(int i = ; i <= n; ++i) {
mm[i] = ((i & (i - )) == ) ? mm[i - ] + : mm[i - ];
dp[i][] = i;
}
for(int j = ; j <= mm[n]; ++j)
for(int i = ; i + ( << j) - <= n; ++i)
dp[i][j] = rmq[dp[i][j - ]] < rmq[dp[i + ( << (j - ))][j - ]] ? dp[i][j - ] : dp[i + ( << (j - ))][j - ];
} int query(int a, int b) {
if(a > b) swap(a, b);
int k = mm[b - a + ];
return rmq[dp[a][k]] <= rmq[dp[b - ( << k) + ][k]] ? dp[a][k] : dp[b - ( << k) + ][k];
}
}; struct Edge{
int to, next;
}; Edge edge[MAXN * ];
int tot, head[MAXN]; int F[MAXN * ];
int P[MAXN];
int cnt;
ST st; void init() {
tot = ;
memset(head, -, sizeof(head));
} void addedge(int u, int v) {
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
} int d[MAXN]; void dfs(int u, int pre, int dep) {
d[u] = dep;
F[++cnt] = u;
rmq[cnt] = dep;
P[u] = cnt;
for(int i = head[u]; i != -; i = edge[i].next) {
int v = edge[i].to;
if(v == pre) continue;
dfs(v, u, dep + );
F[++cnt] = u;
rmq[cnt] = dep;
}
} void LCA_init(int root, int node_num) {
cnt = ;
dfs(root, root, );
st.init( * node_num - );
} int query_lca(int u, int v) {
return F[st.query(P[u], P[v])];
} int main()
{
int T, N, u, v;
scanf("%d", &N);
init();
for(int i = ; i < N; ++i) {
scanf("%d%d", &u, &v);
addedge(u, v);
addedge(v, u);
}
LCA_init(, N); long long ans = ;
for(int i = ; i + i <= N; ++i) {
for(int j = i + i; j <= N; j += i) {
ans += d[i] + d[j] + - * d[query_lca(i, j)];
}
}
printf("%lld\n", ans); return ;
}

Tourists Gym - 101002I LCA——dfs+RMQ在线算法的更多相关文章

  1. POJ 1470 Closest Common Ancestors (LCA, dfs+ST在线算法)

    Closest Common Ancestors Time Limit: 2000MS   Memory Limit: 10000K Total Submissions: 13370   Accept ...

  2. POJ 1330 Nearest Common Ancestors (LCA,dfs+ST在线算法)

    Nearest Common Ancestors Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 14902   Accept ...

  3. LCA(最近公共祖先)——dfs+ST 在线算法

    一.前人种树 博客:浅谈LCA的在线算法ST表 二.沙场练兵 题目:POJ 1330 Nearest Common Ancestors 题解博客:http://www.cnblogs.com/Miss ...

  4. POJ - 1330 Nearest Common Ancestors(dfs+ST在线算法|LCA倍增法)

    1.输入树中的节点数N,输入树中的N-1条边.最后输入2个点,输出它们的最近公共祖先. 2.裸的最近公共祖先. 3. dfs+ST在线算法: /* LCA(POJ 1330) 在线算法 DFS+ST ...

  5. POJ 1330 Nearest Common Ancestors (dfs+ST在线算法)

    详细讲解见:https://blog.csdn.net/liangzhaoyang1/article/details/52549822 zz:https://www.cnblogs.com/kuang ...

  6. LCA最近公共祖先 ST+RMQ在线算法

    对于一类题目,是一棵树或者森林,有多次查询,求2点间的距离,可以用LCA来解决.     这一类的问题有2中解决方法.第一种就是tarjan的离线算法,还有一中是基于ST算法的在线算法.复杂度都是O( ...

  7. LCA(倍增在线算法) codevs 2370 小机房的树

    codevs 2370 小机房的树 时间限制: 1 s  空间限制: 256000 KB  题目等级 : 钻石 Diamond 题目描述 Description 小机房有棵焕狗种的树,树上有N个节点, ...

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

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

  9. [CF 191C]Fools and Roads[LCA Tarjan算法][LCA 与 RMQ问题的转化][LCA ST算法]

    参考: 1. 郭华阳 - 算法合集之<RMQ与LCA问题>. 讲得很清楚! 2. http://www.cnblogs.com/lazycal/archive/2012/08/11/263 ...

随机推荐

  1. MapReduce错误之Error: java.lang.RuntimeException: java.lang.NoSuchMethodException的解决方法

    今天跑MapReduce项目的时候遇到了这个问题,日志如下所示: // :: DEBUG ipc.ProtobufRpcEngine: Call: getDiagnostics took 19ms E ...

  2. 自定义Spring Security的身份验证失败处理

    1.概述 在本快速教程中,我们将演示如何在Spring Boot应用程序中自定义Spring Security的身份验证失败处理.目标是使用表单登录方法对用户进行身份验证. 2.认证和授权(Authe ...

  3. java容器集合

    java 集合分为 Collection 和 Map 两大类 Collection 是 Java 集合框架的顶层接口,它是对容器类进行增.删.改.查的定义,同时继承了 Iterable 接口,具有对集 ...

  4. JVM垃圾回收机制四

    GCRoots与可达性分析 Java中的四种引用 强引用.软引用.弱引用.虚引用.这四种引用的强度是逐渐减弱的,JVM垃圾回收的力度是逐渐增强的. 四种引用的作用 1.可以让程序员通过代码来控制对象的 ...

  5. IO(转换流、缓冲流)

    第1章 转换流 在学习字符流(FileReader.FileWriter)的时候,其中说如果需要指定编码和缓冲区大小时,可以在字节流的基础上,构造一个InputStreamReader或者Output ...

  6. 开发中遇到的Cause: java.sql.SQLException: connection holder is null的异常

    异常的出现是属于获取连接超时,从而找不到持有者. 项目中的配置体现: <property name="removeAbandoned" value="true&qu ...

  7. R语言笔记2

    <13: Simulation> > sample(1:6,4,replace=TRUE) [1] 4 5 2 6 在1-6的整数中随机生成4个整数,且数字可以重复,即每个数字均可重 ...

  8. Objective-C Inheritance

    One of the most important concepts in object-oriented programming is that of inheritance. Inheritanc ...

  9. python(一)

    1 python安装 先安装python,之后安装pycharm 创建工程时需要关联解释器路径: 2 python运行 先编译后解释 .py--.pyc文件---解析----结果 .pyc的目的是减少 ...

  10. selenium+python之自动换测试用例执行

    1.一个用例为一个完整的场景,从用户登陆系统到最终退出并关闭浏览器. 2.一个用例只验证一个功能点,不要试图在用户登陆系统后把所有的功能都验证一遍. 3.尽可能少的编写逆向逻辑用例.一方面因为逆向逻辑 ...