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. 软件模拟I2C时输入与输出切换

    一 为达到类似C51的操作需要添加以下位带操作:#include "stm32f10x_gpio.h"#include "stm32f10x_conf.h" / ...

  2. LWIP学习之流程架构

    一 STM32F107的网络接口配置:#include "stm32_eth.h" 1.1 打开网口时钟,响应IO配置.NVIC中断:通过调用Ethernet_Configurat ...

  3. DevExpress GridControl 控件二表连动

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  4. MDX属性查询

    SELECT NON EMPTY { { { { { AddCalculatedMembers([会员.会员ID].[会员ID].Members), [会员.会员ID].[(All)] } } } } ...

  5. Shell分割字符得到数组

    #!/bin/bash p=$(hadoop fs -ls /tgl/data |awk '{print $8}') #要将$a分割开,先存储旧的分隔符 OLD_IFS="$IFS" ...

  6. OpenCV ——IplImage应用解析

    由于OpenCV主要针对的是计算机视觉方面的处理,因此在函数库中,最重要的结构体是IplImage结构.IplImage结构来源于Intel的另外一个函数库Intel Image Processing ...

  7. Java函数的传参机制

    一 最近的一个项目,里面各种返回void,参数用引用类型,那叫一个熟和多,但是也把我绕糊涂了. 我就打算好好理一理java的传参机制,整理一番 二 很多人一听Java的传参,那一定会脱口而出,java ...

  8. H5gulp版非前后的分离环境

    由于公司不同意我们使用前后端分离进行开发,硬是要我们和PHP混合在一起,所以用gulp搭建了一个简单的手脚架来用 目录结构: 主要是gulpfile.js里的内容 var gulp = require ...

  9. 30个提高Web程序执行效率的好经验

    尽量避免使用DOM.当需要反复使用DOM时,先把对DOM的引用存到JavaScript本地变量里再使用.使用设置innerHTML的方法来替换document.createElement/append ...

  10. 数据库(数据库、表及表数据、SQL语句)

    数据库MYSQL 今日内容介绍 u MySQL数据库 u SQL语句 第1章 数据库 1.1 数据库概述 l 什么是数据库 数据库就是存储数据的仓库,其本质是一个文件系统,数据按照特定的格式将数据存储 ...