第一行两个整数N(1 < N <= 105)、K(1 <= K <= 105)
第2~N行,每行两个整数a、b(1 <= a,b <= N),表示a是b的父亲。
第N+1~N+K+1行,每行两个整数a、b(1 <= a,b <= N),表示询问a和b的最近公共祖先是谁。
标签:定义 是什么 EDA log 注意 main names 最近公共祖先 algorithm
题目:
给定N个节点的一棵树,有K次查询,每次查询a和b的最近公共祖先。
第一行两个整数N(1 < N <= 105)、K(1 <= K <= 105)
第2~N行,每行两个整数a、b(1 <= a,b <= N),表示a是b的父亲。
第N+1~N+K+1行,每行两个整数a、b(1 <= a,b <= N),表示询问a和b的最近公共祖先是谁。
输出K行,第i行表示第i个查询的最近公共祖先是谁。
1 #include<cstdio> 2 #include<algorithm> 3 #include<iostream> 4 #include<cmath> 5 #include<cstring> 6 using namespace std; 7 int f[100001][20]; 8 int next[200010]; 9 int to[200010]; 10 int head[200010]; 11 int d[200001]; 12 int tot=0; 13 int n,m; 14 int x,y; 15 void add(int x,int y) 16 { 17 tot++; 18 next[tot]=head[x]; 19 head[x]=tot; 20 to[tot]=y; 21 } 22 void dfs(int x) 23 { 24 d[x]=d[f[x][0]]+1; 25 for(int i=1;i<=19;i++) 26 { 27 f[x][i]=f[f[x][i-1]][i-1]; 28 } 29 for(int i=head[x];i;i=next[i]) 30 { 31 dfs(to[i]); 32 } 33 } 34 int lca(int x,int y) 35 { 36 if(d[x]<d[y]) 37 { 38 swap(x,y); 39 } 40 int dep=d[x]-d[y]; 41 for(int i=0;i<=19;i++) 42 { 43 if((dep&(1<<i))!=0) 44 { 45 x=f[x][i]; 46 } 47 } 48 if(x==y) 49 { 50 return x; 51 } 52 for(int i=19;i>=0;i--) 53 { 54 if(f[x][i]!=f[y][i]) 55 { 56 x=f[x][i]; 57 y=f[y][i]; 58 } 59 } 60 return f[x][0]; 61 } 62 int main() 63 { 64 scanf("%d%d",&n,&m); 65 for(int i=1;i<=n;i++) 66 { 67 f[i][0]=i; 68 } 69 for(int i=1;i<n;i++) 70 { 71 scanf("%d%d",&x,&y); 72 f[y][0]=x; 73 add(x,y); 74 } 75 for(int i=1;i<=n;i++) 76 { 77 if(f[i][0]==i) 78 { 79 dfs(i); 80 break; 81 } 82 } 83 for(int i=1;i<=m;i++) 84 { 85 scanf("%d%d",&x,&y); 86 printf("%d\n",lca(x,y)); 87 } 88 }
最近公共祖先(Least Common Ancestors)——倍增LCA
标签:定义 是什么 EDA log 注意 main names 最近公共祖先 algorithm
原文地址:https://www.cnblogs.com/Khada-Jhin/p/8973949.html