LCA算法_普通做法&倍增&Tarjan&RMQ
Posted abby2306496726
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LCA算法_普通做法&倍增&Tarjan&RMQ相关的知识,希望对你有一定的参考价值。
题目:POJ-1330
题目大意:给你一棵含有n个结点的树,n-1条边,问两个结点的最近公共祖先是哪个节点。
普通做法
思路:让两个结点到达同一深度,再一起往上走,到达同一结点即为最近公共祖先。
例:3和7,让3往上走到16,与7同一深度后,再一起一步步往上走,到达4时,为同一个结点,即为其最近公共祖先。
基本步骤:1、邻接表存图(这里用到的是vector)
2、dfs出各个结点的深度
3、让深度较高的往上走,走到同一深度
4、两个结点一起往上走,走到同一个结点并输出
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 using namespace std; 5 6 const int maxn=10005; 7 vector<int> son[maxn]; 8 int n; 9 int p[maxn],in[maxn],dep[maxn]; 10 11 //dfs获取结点深度 12 void dfs(int root,int depth){ 13 dep[root]=depth; 14 for(int i=0;i<son[root].size();i++){ 15 p[son[root][i]]=root; 16 dfs(son[root][i],depth+1); 17 } 18 return; 19 } 20 21 //LCA普通做法核心步骤 22 int LCA(int u,int v){ 23 while(dep[u]>dep[v]) u=p[u]; 24 while(dep[v]>dep[u]) v=p[v]; 25 while(u!=v){ 26 u=p[u]; 27 v=p[v]; 28 } 29 return u; 30 } 31 32 int main(){ 33 int T,a,b,u,v;//T个测试样例 34 scanf("%d",&T); 35 while(T--){ 36 scanf("%d",&n); 37 for(int i=1;i<=n;i++) 38 son[i].clear(); 39 memset(in,0,sizeof(in)); 40 for(int i=1;i<n;i++){ 41 scanf("%d%d",&a,&b); 42 son[a].push_back(b); 43 //代表b是父结点的个数 44 in[b]++; 45 } 46 memset(dep,0,sizeof(dep)); 47 int root=0; 48 for(int i=1;i<=n;i++) 49 if(in[i]==0) root=i; 50 p[root]=0; 51 dfs(root,0); 52 scanf("%d%d",&u,&v); 53 printf("%d\\n",LCA(u,v)); 54 } 55 return 0; 56 } 57 58 /* 59 1 60 16 61 1 14 62 8 5 63 10 16 64 5 9 65 4 6 66 8 4 67 4 10 68 1 13 69 6 15 70 10 11 71 6 7 72 10 2 73 16 3 74 8 1 75 16 12 76 16 7 77 */
以上是关于LCA算法_普通做法&倍增&Tarjan&RMQ的主要内容,如果未能解决你的问题,请参考以下文章
bzoj 1787 && bzoj 1832: [Ahoi2008]Meet 紧急集合(倍增LCA)算法竞赛进阶指南
洛谷T1967 货车运输 Kruskal最大生成树&&倍增LCA