LCA近期公共祖先
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近期公共祖先的更多相关文章
- LCA 近期公共祖先 小结
LCA 近期公共祖先 小结 以poj 1330为例.对LCA的3种经常使用的算法进行介绍,分别为 1. 离线tarjan 2. 基于倍增法的LCA 3. 基于RMQ的LCA 1. 离线tarjan / ...
- 连通分量模板:tarjan: 求割点 && 桥 && 缩点 && 强连通分量 && 双连通分量 && LCA(近期公共祖先)
PS:摘自一不知名的来自大神. 1.割点:若删掉某点后.原连通图分裂为多个子图.则称该点为割点. 2.割点集合:在一个无向连通图中,假设有一个顶点集合,删除这个顶点集合,以及这个集合中全部顶点相关联的 ...
- POJ 1470 Closest Common Ancestors【近期公共祖先LCA】
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/u013912596/article/details/35311489 题目链接:http://poj ...
- 近期公共祖先(LCA)——离线Tarjan算法+并查集优化
一. 离线Tarjan算法 LCA问题(lowest common ancestors):在一个有根树T中.两个节点和 e&sig=3136f1d5fcf75709d9ac882bd8cfe0 ...
- HDU 2586 How far away ?(LCA模板 近期公共祖先啊)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 Problem Description There are n houses in the vi ...
- POJ1330Nearest Common Ancestors——近期公共祖先(离线Tarjan)
http://poj.org/problem? id=1330 给一个有根树,一个查询节点(u,v)的近期公共祖先 836K 16MS #include<iostream> #includ ...
- LintCode 近期公共祖先
中等 近期公共祖先 查看执行结果 34% 通过 给定一棵二叉树,找到两个节点的近期公共父节点(LCA). 近期公共祖先是两个节点的公共的祖先节点且具有最大深度. 您在真实的面试中是否遇到过这个题? Y ...
- lca 最近公共祖先
http://poj.org/problem?id=1330 #include<cstdio> #include<cstring> #include<algorithm& ...
- Tarjan算法应用 (割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)问题)(转载)
Tarjan算法应用 (割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)问题)(转载) 转载自:http://hi.baidu.com/lydrainbowcat/blog/item/2 ...
随机推荐
- navigator.geolocation在IOS10系统中无法定位问题
在使用地图需要定位的朋友都可能遇到这个问题,参考的文章说的是用百度地图,我用的是腾讯地图,但是其中的原理差不多.所以谢谢这些提供资源的大神们. if (navigator.geolocation) { ...
- html 空白汉字占位符
可以看作一个空白的汉字 == 普通的英文半角空格 == == == no-break space (普通的英文半角空格但不换行) == 中文全角空格 (一个中文宽度) == ...
- TreeListControl 不同类别的行使用不同的数据模板
- 关于json与protobuf的材料
1. https://solicomo.com/network-dev/protobuf-proto3-vs-proto2.html 2.
- 把系统时间改到以前后,MyEclipse9.1的工程里的JS文件修改完保存但MyEclipse不会将其不会更新。
一个任务中,由于本周数据还没有产生,只好把系统时间修改到上周,利用下上周的数据. 修改内容主要是增加查询子句的一个字段,因此,包含SQL的DAO,前台显示的Table和前台操作的JS都需要相应修改,它 ...
- html5游戏驴子跳
在线演示 免费下载 分享一款HTML5开发的游戏,放松一下吧大家吧
- 破解无线网络密码-BT3如何使用3
BT3 虚拟机 SNOOPWEP2 破解无线网络WEP密钥图解 1.下载BT3 光盘映像文件(ISO格式),比如:bt3-final.iso: 用WinISO 或 UltraISO(这个还支持DVD ...
- ORACLE常用监控语句(未完待续)
--查询日志的切换频率 select t1.RECID as srecid ,t2.RECID as erecid ,t1.FIRST_TIME as stime ...
- gradle 项目转成maven项目
找到一个个子项目目录下的build.gradle文件,在文件开头添加以下内容: apply plugin: 'java' apply plugin: 'maven' compileJava.optio ...
- 修改ligerui 默认确认按钮
$.extend($.ligerDefaults.DialogString, {ok: '取消单据'}); showDialogPay = $.ligerDialog.alert('正在支付中,请稍候 ...