对于LCA的一些理解

RMQ
  • dfs处理树
    对于一个树形结构,可以用dfs将一颗树转化成数组,数组中记录每个点的标号,这样数组就按照dfs的顺序把树存了下来

  • 确定祖先的范围
    对于询问的节点X和Y, X、Y的祖先一定存在于数组中X、Y第一次出现的区间内,而且祖先就是区间内深度最小的节点

  • RMQ
    dfs的复杂度就是树边数的二倍,所以区间查询需要优化,这里可以用RMQ算法,预处理结果O(1)得到最值

void dfs(int pre, int x, int step) {depth[x] = step;first[x] = cnt;tree[cnt] = x;cnt++;int len = g[x].size();for (int i = 0; i < len; ++i) {if (g[x][i] == pre) continue;dfs(x, g[x][i], step + 1);tree[cnt++] = x;}return;
}
int Min(int a, int b) {if (depth[a] < depth[b])    return a;else    return b;
}
void RMQ() {for (int i = 1; i <= cnt; ++i) {dp[i][0] = tree[i];}for (int i = 1; (1 << i) <= cnt; ++i) {for (int j = 1; j + (1 << i) - 1 <= cnt; ++j) {dp[j][i] = Min(dp[j][i - 1], dp[j + (1 << (i - 1))][i - 1]);}}
}
int LCA(int a, int b) {int l = first[a];int r = first[b];if (l > r)  swap(l, r);int len = log2(r - l + 1);return Min(dp[l][len], dp[r - (1 << len) + 1][len]);
}

树上倍增

father[ i ] [ j ]表示 i 的第 2 ^ j 个父亲

  • dfs
    dfs在处理深度的同时更新每个人的father数组
void dfs(int pre, int x) {// 更新fatherfor (int i = 1; i <= log2(n); ++i) {if (fa[x][i - 1] == 0)  break;fa[x][i] = fa[fa[x][i - 1]][i - 1];}// 记录深度depth[x] = depth[pre] + 1;int len = g[x].size();for (int i = 0; i < len; ++i) {int son = g[x][i];if (son == pre) continue;fa[son][0] = x;dfs(x, son);}
}
  • LCA
    首先将两个节点的深度调成一样,如果深度相同而且是同一个点就找到最近的祖先了,如果深度相同但是节点不同,这时就要向上倍增,需要注意的是倍增的中止条件不是两个节点相同,而是节点的父亲相同。因为每次倍增的范围很大,很可能超过最近公共祖先,我们可以从最大的祖先开始,如果祖先相同缩小范围,如果祖先不同更新两个点的状态继续找,最后两个人的最近公共祖先一定是father[ i ][ 0 ]
int LCA(int a, int b) {if (depth[a] < depth[b])  swap(a, b);int depth_x = depth[a] - depth[b];// 先将两个点的深度调成一样for (int i = 0; i <= log2(depth_x); ++i) {if (depth_x & (1 << i))a = fa[a][i];}// 如果深度一样,而且相同直接返回if (a == b) return a;// 从最远的父亲开始for (int i = log2(depth[a]); i >= 0; --i) {// 如果父亲不同就向上更新if (fa[a][i] != fa[b][i]) {a = fa[a][i];b = fa[b][i];}}return fa[a][0];
}

Tarjan

完美结合并查集dfs 在**O(n + q)**解决LCA问题。
dfs的时候需要做以下处理:

  • 对于当前点x来说:如果存在询问(x,y),而且y已经dfs访问过,那么LCA就是 find(y)
  • 回溯的时候要将son的祖先设置为x(子树的祖先始终为根节点
int n;
LL dp[maxn], ans[maxn];
int pre[maxn], vis[maxn];
struct ac{int v, d;
};
vector<ac> G[maxn], Q[maxn];int find(int x) {return x == pre[x] ? x : pre[x] = find(pre[x]);
}void Tarjan(int fa, int x) {vis[x] = 1;// 更新询问for (auto it : Q[x]) {if (!vis[it.v]) continue;ans[it.d] = dp[x] + dp[it.v] - 2 * dp[find(it.v)];}for (auto it : G[x]) {if (it.v == fa) continue;dp[it.v] = dp[x] + it.d;Tarjan(x, it.v);pre[it.v] = x; // 更新祖先}// for (int i = 0; i < (int)Q[x].size(); ++i) {//  if (!vis[ Q[x][i].v ]) continue;//  ans[ Q[x][i].d ] = dp[x] + dp[ Q[x][i].v ] - 2 * dp[find( Q[x][i].v )];// }// for (int i = 0; i < (int)G[x].size(); ++i) {//    int son = G[x][i].v;//     if (son == fa) continue;//    dp[ G[x][i].v ] = dp[x] + G[x][i].d;//    Tarjan(x, son);//   pre[ G[x][i].v ] = x; // }
}
求树上两点的距离

树上两点的距离是唯一的,距离 = depth[X] + depth[Y] - 2 * depth[ancestor]

线段重合的长度

思想和求距离一样,例如A到C和B到C的重合长度 = (dis_ac + dis_bc - dis_ab)/ 2

int dis(int a, int b) {int ancestor = LCA(a, b);int depth_a = depth[a];int depth_b = depth[b];int depth_ancestor = depth[ancestor];return depth_a + depth_b - 2 * depth_ancestor;
}

LCA 最近公共祖先(RMQ、树上倍增、Tarjan),树上两点距离,线段重合长度相关推荐

  1. LCA(最近公共祖先)问题

    1.这个算法基于并查集和深度优先搜索.算法从根开始,对每一棵子树进行深度优先搜索,访问根时,将创建由根结点构建的集合,然后对以他的孩子结点为根的子树进行搜索,使对于 u, v 属于其某一棵子树的 LC ...

  2. Tarjan算法应用 (割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)问题)...

    转载自:http://hi.baidu.com/lydrainbowcat/blog/item/2194090a96bbed2db1351de8.html 基本概念: 1.割点:若删掉某点后,原连通图 ...

  3. POJ 1330 LCA最近公共祖先 离线tarjan算法

    题意要求一棵树上,两个点的最近公共祖先 即LCA 现学了一下LCA-Tarjan算法,还挺好理解的,这是个离线的算法,先把询问存贮起来,在一遍dfs过程中,找到了对应的询问点,即可输出 原理用了并查集 ...

  4. 故事篇之 LCA 最近公共祖先(一)

    故事出真知 阿珍 爱上了 阿强 但 被他们的父母 拒绝 了 没错 狗血的近亲结婚剧情开始了 阿珍 说: 不行,我深深爱着我的阿强,谁也不能把我们分开 阿强 深情地望着阿珍 说 一定会有机会的! 此时 ...

  5. LCA(最近公共祖先)(leetcode 236 python C++)

    LCA(Lowest Common Ancestors),即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先. # Definition for a binary tree node. ...

  6. LCA 最近公共祖先

    LCA ,也就是最近公共祖先是什么意思呢. 下面这张图可能会让你清楚的明白什么是最近公共祖先. 对于初始点,前提是它能构成一棵不成环的树,之所以不能成环,从定义就看出来了嘛,如果成环,是不是有种1是3 ...

  7. CodeForces - 208E Blood Cousins(树上倍增+二分/树上启发式合并)

    题目链接:点击查看 题目大意:给出n棵树,再给出m个询问,每次询问给出两个整数u和k,先假设u在k层之上的祖先是p,问与u在同一层深度,并且公共祖先都是p的节点有多少个 题目分析:因为先要求出u在第k ...

  8. 模板 - LCA最近公共祖先(倍增法、Tarjan、树上差分、LCA优化的次小生成树)

    整理的算法模板合集: ACM模板 注意x和y的LCA可以是x或者y本身 一.LCA的在线倍增算法 /*给定一棵包含 n个节点的有根无向树,有 m个询问,每个询问 给出了一对节点的编号 x和 y,询问 ...

  9. LCA 最近公共祖先 详解

    一.内容 给定一棵包含 n 个节点的有根无向树,节点编号互不相同,但不一定是 1∼n.有 m 个询问,每个询问给出了一对节点的编号 x 和 y,询问 x 与 y 的祖孙关系.输入格式 输入第一行包括一 ...

最新文章

  1. ASP.NET 2.0中如何连接到Mysql(转)
  2. 关于服务器虚化的优势,服务器虚拟化优缺点总结
  3. NR 5G AMF重定向的注册流程
  4. nodejs,python,sublime和Eclipse的包管理器
  5. yii 使用 有赞sdk_有赞ABTest系统:数据驱动增长实践
  6. 单循环链表中设置尾指针比设置头指针更好的原因
  7. IDC报告:中国公有云服务市场同比增长49.7%,领跑全球
  8. 使用monkey 前准备工作
  9. Idea添加Jetty时提示JMX module is not included
  10. 软考网络工程师--数据通信基础
  11. 字符串转换为合法IP地址
  12. IntelliJ IDEA 必备的快捷键大全
  13. Qt样式表Qss(什么是QSS;基本语法;setStyleSheet函数;样式表的属性值;利用QtCreate实现样式切换;样式表实现皮肤改变实例)
  14. C# “配置系统未能初始化”
  15. php7中shal(),十个你需要在 PHP 7 中避免的坑
  16. 设计模式——装饰模式Decorate
  17. MOS管开启过程中VGS的台阶——米勒平台?
  18. 易道云控数字引擎下的企业协同办公
  19. 2020年jQuery笔试题汇总整理
  20. 基于python的可视化分析_Python数据的可视化分析,python

热门文章

  1. JS实现全选、反选、不选
  2. js原生捕鱼达人(一)
  3. Eclipse+pyDev进行Python环境的搭建
  4. PHP LOG使用心得(2)
  5. SQL server注入
  6. [网络安全提高篇] 一〇六.SQL注入之手工注入和SQLMAP入门案例详解
  7. 2013\National _Java_A\3.埃及分数
  8. 10.2.2 选择器
  9. Go语言生成区间随机数
  10. 2018年第九届蓝桥杯 - 国赛 - C/C++大学B组 - B. 激光样式