【模板】
【问题描述】
给定一棵有n个节点的树,m此询问,每次询问点x和点y的最近公共祖先。
【输入格式】
第一行一个n,表示这棵树有n个结点。接下来n-1行,每行两个数下x,y,表示下x,y之间有一条边。
然后一个整数m,表示有m个询问,接下来m行,每行两个整数x,y,表示询问点x和点y的最近公共祖先。
【输出格式】
输出m行,表示询问的结果。
【输入样例】
6
1 2
1 3
2 4
2 5
3 6
2
4 5
2 6
【输出样例】
2
1
数据范围
1<=n<=100000;
1<=m<=200;
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<vector> #include<queue> #include<set> #include<map> #include<ctime> using namespace std; const int maxn = 100000 + 10 ; const int maxk = 20 + 1 ; struct Node {int to,next;}edge[maxn*2]; int head[maxn * 2],cnt; void add(int x,int y) { edge[++cnt].to=y; edge[cnt].next=head[x]; head[x]=cnt; } int n,m,Dep[maxn],f[maxn][maxk];//f[x][k]表示x的2^k辈祖先; void Deal_first(int pos,int fa) { Dep[pos]=Dep[fa]+1; for(int i=0;i<=19;i++) f[pos][i+1]=f[f[pos][i]][i]; for(int i=head[pos];i;i=edge[i].next) { int son = edge[i].to; if(son==fa) continue; f[son][0]=pos; Deal_first(son,pos); } } int LCA(int x,int y) { if(Dep[x]<Dep[y]) swap(x,y); for(int i=20;i>=0;i--) { if(Dep[f[x][i]]>=Dep[y]) x=f[x][i]; if(x==y) return x; } for(int i=20;i>=0;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0]; } int main() { scanf("%d",&n); for(int i=1,a,b;i<n;i++) { scanf("%d%d",&a,&b); add(a,b);add(b,a); } Deal_first(1,0); scanf("%d",&m); while(m--) { int a,b; scanf("%d%d",&a,&b); printf("%d\n",LCA(a,b)); } return 0; }
原文:https://www.cnblogs.com/hfang/p/10847764.html