LCA近期公共祖先

该分析转之:http://kmplayer.iteye.com/blog/604518

1,并查集+dfs

对整个树进行深度优先遍历。并在遍历的过程中不断地把一些眼下可能查询到的而且结果同样的节点用并查集合并.



2,分类。使每一个结点都落到某个类中,到时候仅仅要运行集合查询,就能够知道结点的LCA了。

对于一个结点u.类别有:

以u为根的子树、除类一以外的以f(u)为根的子树、除前两类以外的以f(f(u))为根的子树、除前三类以外的以f(f(f(u)))为根的子树……



类一的LCA为u,类二为f(u),类三为f(f(u)),类四为f(f(f(u)))。这种分类看起来好像并不困难。

但关键是查询是二维的。并没有一个确定的u。接下来就是这个算法的巧妙之处了。

利用递归的LCA过程。

当lca(u)运行完成后,以u为根的子树已经所有并为了一个集合。而一个lca的内部实际上做了的事就是对其子结点。依此调用lca.

当v1(第一个子结点)被lca。正在处理v2的时候,以v1为根的子树+u同在一个集合里。f(u)+编号比u小的u的兄弟的子树 同在一个集合里,f(f(u)) + 编号比f(u)小的 f(u)的兄弟 的子树 同在一个集合里…… 


而这些集合,对于v2的LCA都是不同的。

因此仅仅要查询x在哪一个集合里,就能知道LCA(v2,x)



另一种可能。x不在不论什么集合里。当他是v2的儿子,v3,v4等子树或编号比u大的u的兄弟的子树(等等)时。就会发生这样的情况。即还没有被处理。

还没有处理过的怎么办?把一个查询(x1,x2)往查询列表里加入两次,一次加入到x1的列表里,一次加入到x2的列表里,假设在做x1的时候发现 x2已经被处理了。那就接受这个询问。(两次中必然仅仅有一次询问被接受).

#include <iostream>
#include <algorithm>
#include <vector>
#include <cstdio>
#include <cstring>
using namespace std; const int MAXN = 100000 + 10;
int degree[MAXN];
bool vst[MAXN];
int ancestor[MAXN];
int f[MAXN];
int rank[MAXN];
vector<int> tree[MAXN];
vector<int> Qes[MAXN]; int N;
void init(){
for(int i = 0;i <= N;++i){
degree[i] = 0;
vst[i] = false;
ancestor[i] = -1;
f[i] = i;
rank[i] = 0;
tree[i].clear();
Qes[i].clear();
}
} int find(int x){
if(x == f[x])
return x;
return f[x] = find(f[x]);
} void setUnion(int u,int v){
int a = find(u),b = find(v);
if(a != b){
if(rank[a] < rank[b]){
f[a] = b;
} else {
f[b] = a;
if(rank[a] == rank[b]) rank[a]++;
}
}
} void LCA(int u){
ancestor[u] = u;
int sz = tree[u].size();
for(int i = 0;i < sz;++i){
LCA(tree[u][i]);
setUnion(u,tree[u][i]);
ancestor[find(u)] = u;
} vst[u] = 1;
sz = Qes[u].size();
for(int i = 0;i < sz;++i){
if(vst[Qes[u][i]]){
printf("%d\n",ancestor[find(Qes[u][i])]);
return;
}
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
int x,y;
scanf("%d",&N);
init();
for(int i = 1;i < N;++i){
scanf("%d%d",&x,&y);
degree[y]++;
tree[x].push_back(y);
} int s,t;
scanf("%d%d",&s,&t);
Qes[s].push_back(t);
Qes[t].push_back(s); for(int i = 1;i <= N;++i){
if(degree[i] == 0){
LCA(i);
break;
}
}
}
return 0;
}

LCA近期公共祖先的更多相关文章

  1. LCA 近期公共祖先 小结

    LCA 近期公共祖先 小结 以poj 1330为例.对LCA的3种经常使用的算法进行介绍,分别为 1. 离线tarjan 2. 基于倍增法的LCA 3. 基于RMQ的LCA 1. 离线tarjan / ...

  2. 连通分量模板:tarjan: 求割点 &amp;&amp; 桥 &amp;&amp; 缩点 &amp;&amp; 强连通分量 &amp;&amp; 双连通分量 &amp;&amp; LCA(近期公共祖先)

    PS:摘自一不知名的来自大神. 1.割点:若删掉某点后.原连通图分裂为多个子图.则称该点为割点. 2.割点集合:在一个无向连通图中,假设有一个顶点集合,删除这个顶点集合,以及这个集合中全部顶点相关联的 ...

  3. POJ 1470 Closest Common Ancestors【近期公共祖先LCA】

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/u013912596/article/details/35311489 题目链接:http://poj ...

  4. 近期公共祖先(LCA)——离线Tarjan算法+并查集优化

    一. 离线Tarjan算法 LCA问题(lowest common ancestors):在一个有根树T中.两个节点和 e&sig=3136f1d5fcf75709d9ac882bd8cfe0 ...

  5. HDU 2586 How far away ?(LCA模板 近期公共祖先啊)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 Problem Description There are n houses in the vi ...

  6. POJ1330Nearest Common Ancestors——近期公共祖先(离线Tarjan)

    http://poj.org/problem? id=1330 给一个有根树,一个查询节点(u,v)的近期公共祖先 836K 16MS #include<iostream> #includ ...

  7. LintCode 近期公共祖先

    中等 近期公共祖先 查看执行结果 34% 通过 给定一棵二叉树,找到两个节点的近期公共父节点(LCA). 近期公共祖先是两个节点的公共的祖先节点且具有最大深度. 您在真实的面试中是否遇到过这个题? Y ...

  8. lca 最近公共祖先

    http://poj.org/problem?id=1330 #include<cstdio> #include<cstring> #include<algorithm& ...

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

    Tarjan算法应用 (割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)问题)(转载) 转载自:http://hi.baidu.com/lydrainbowcat/blog/item/2 ...

随机推荐

  1. 还原JavaScript的真实历史~

    问题 ============ JavaScript真的继承自Cmm吗? JavaScript与Java有多少关系? JavaScirpt最初的设计是怎样的?在许多资料,JavaScript的语源被追 ...

  2. 俄罗斯水手 [C#] 对List<T>取交集、连集及差集

    ※本文使用int為例,若為使用自訂之DataModel,需實作IEquatable<T>介面才能使用 1.  取交集 (A和B都有) List A : { 1 , 2 , 3 , 5 , ...

  3. [转载]Elasticsearch索引重建(Rebuild)

    From:http://blog.csdn.net/changong28/article/details/38491185 索引重建(Rebuild) 索引创建后,你可以在索引当中添加新的类型,在类型 ...

  4. Unity异步加载场景loading条

    using UnityEngine; using System.Collections; public class LoadingScene : MonoBehaviour { public UISl ...

  5. 【5】基于Log4Net的日志系统

    阅读目录 日志系统应具备的特性  Log4Net 配置文件:log4net.config 初始化 输出信息 对Log4Net的封装 log4net.config复杂配置   不管是Web应用程序还是W ...

  6. Jade的奇怪解析问题。

    如下的jade代码: span#span1 Span#span2   解析的时候span2总是变成span1的子元素.怎么解决? [解决方法] 用如下的代码就可以了. span#span1 |   s ...

  7. 为什么要使用href=”javascript:void(0);”?

    JavaScript中语句最后的分号是可以缺省的,那为何要使用javascript:;而不是javascript:呢? 是习惯还是规范,我疑惑了! 具有代码洁癖的coder们,没事多写一个分号,圣洁的 ...

  8. 两条Find指令

    # 列出所有包括a@b.c内容的xml文件 find / -type f -name "*.xml" | xargs grep "a@b.c" # 列出/opt ...

  9. Java8新特性 - Lambda表达式 - 基本知识

    A lambda expression is an unnamed block of code (or an unnamed function) with a list of formal param ...

  10. UIScrollView 图片循环滚动

    1:假如有6个图片:那个,Scrollview的大小加 7 个图片的大小 2: //ImageScrollView; UIScrollView *imageScroll = [[UIScrollVie ...