LCA--P3379 模板最近公共祖先(LCA)
Posted very-beginning
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LCA--P3379 模板最近公共祖先(LCA)相关的知识,希望对你有一定的参考价值。
题目描述
如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。
输入格式
第一行包含三个正整数 N,M,S,分别表示树的结点个数、询问的个数和树根结点的序号。
接下来 N−1 行每行包含两个正整数 x,y,表示 x 结点和 y 结点之间有一条直接连接的边(数据保证可以构成树)。
接下来 M 行每行包含两个正整数 a,b,表示询问 a 结点和 b 结点的最近公共祖先。
输出格式
输出包含 M 行,每行包含一个正整数,依次为每一个询问的结果。
设 f [ u ][ k ] 表示 u 的 2k 辈祖先,即从 u 向根节点走 2k 步到达的节点。特别地,若该节点不存在,则令 f [ u ][ k ] = 0 。f [ u ][ 0 ] 就是 x 的父节点。因为 u 向根节点走 2k ⇔ 向根节点走 2k-1 步,再走 2k-1 步。所以对于 k∈ [ 1,logn ] ,有 f [ u ][ k ] = f [ f [ u ][ k-1 ] ][ k-1 ]。
f 数组利用了递推的思想。递推式为: f [ u ][ k ] = f [ f [ u ][ k-1 ] ][ k-1 ]。因此,我们可以对树进行遍历 DFS ,由此得到 f [ u ][ 0 ],再计算出 f 数组的所有值。
计算 LCA( x, y ) 分为以下几步:
①设 dep [ x ] 表示 x 的深度。那么设 dep [ x ] ≥ dep [ y ] 。(否则,可交换 x, y )
②利用二进制拆分的思想,把 x 向上调整到与 y 同一的深度。即:依次尝试从 x 向上走 k = 2logn… 21,20 步,若到达的点比 y 深,则令 x = f [ x ][ k ]。
③若此时的 x = y ,则说明已经找到了 LCA ,两点的 LCA 就等于 y 。
④若此时的 x ≠ y ,那么 x, y 同时向上调整,并保持深度一致且二者不会相会。具体来说就是,依次尝试把 x, y 同时向上走 k = 2logn… 21,20 步,若 f [ x ][ k ] ≠ f [ y ][ k ](即仍未相会),则令 x = f [ x ][ k ],y = f [ y ][ k ]。
⑤此时 x,y 必定只差一步就相会了,他们的父节点 f [ x ][ 0 ] 就是 LCA。
1 #include<cstdio> 2 #include<cmath> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<queue> 7 using namespace std; 8 #define maxn 501000 9 int n,m,s; 10 int dep[maxn<<1]; 11 int f[maxn<<1][21]; 12 int head[maxn<<1],cnt=0; 13 struct hh 14 { 15 int nex,to; 16 }t[maxn<<1]; 17 inline void add(int nex,int to) 18 { 19 t[++cnt].nex=head[nex]; 20 t[cnt].to=to; 21 head[nex]=cnt; 22 } 23 inline void Deal_first(int u,int fa) 24 { 25 dep[u]=dep[fa]+1; 26 for(int i=0;i<20;i++) 27 f[u][i+1]=f[f[u][i]][i]; 28 for(int i=head[u];i;i=t[i].nex) 29 { 30 int v=t[i].to; 31 if(v==fa) continue; 32 f[v][0]=u; 33 Deal_first(v,u); 34 } 35 return; 36 } 37 inline int LCA(int x,int y) 38 { 39 if(dep[x]<dep[y]) swap(x,y); 40 for(int i=20;i>=0;i--) 41 { 42 if(dep[f[x][i]]>=dep[y]) x=f[x][i]; 43 if(x==y) return x; 44 } 45 for(int i=20;i>=0;i--) 46 { 47 if(f[x][i]!=f[y][i]) 48 { 49 x=f[x][i]; 50 y=f[y][i]; 51 } 52 } 53 return f[x][0]; 54 } 55 inline int read() 56 { 57 int kr=1,xs=0; 58 char ls; 59 ls=getchar(); 60 while(!isdigit(ls)) 61 { 62 if(!(ls^45)) 63 kr=-1; 64 ls=getchar(); 65 } 66 while(isdigit(ls)) 67 { 68 xs=(xs<<1)+(xs<<3)+(ls^48); 69 ls=getchar(); 70 } 71 return xs*kr; 72 } 73 int main() 74 { 75 int x,y; 76 n=read();m=read();s=read(); 77 for(int i=1;i<n;i++) 78 { 79 x=read();y=read(); 80 add(x,y); 81 add(y,x); 82 } 83 Deal_first(s,0); 84 for(int i=1;i<=m;i++) 85 { 86 x=read();y=read(); 87 printf("%d ",LCA(x,y)); 88 } 89 return 0; 90 }
以上是关于LCA--P3379 模板最近公共祖先(LCA)的主要内容,如果未能解决你的问题,请参考以下文章