LCA
LCA(Least Common Ancestors),即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先。
——百度百科
【模板】
题目描述
如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。
输入输出格式
输入格式:
第一行包含三个正整数N、M、S,分别表示树的结点个数、询问的个数和树根结点的序号。
接下来N-1行每行包含两个正整数x、y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树)。
接下来M行每行包含两个正整数a、b,表示询问a结点和b结点的最近公共祖先。
输出格式:
输出包含M行,每行包含一个正整数,依次为每一个询问的结果。
说明
时空限制:1000ms,128M
数据规模:
对于100%的数据:N<=500000,M<=500000
倍增算法:
1 #include<cstdio> 2 #include<iostream> //swap 3 #define MAXN 500010 4 using namespace std; 5 int n,m,s,tot; 6 int depth[MAXN],fa[MAXN][22],log2[MAXN],head[MAXN]; 7 struct ss 8 { 9 int next,to; 10 }way[MAXN<<1]; 11 void add(int x,int y) 12 { 13 way[++tot].next=head[x]; //next边记录点(x)的第(++tot)出边,head其点为最后一条边 14 way[tot].to=y; //to记录出边指向的点 15 head[x]=tot; 16 } 17 void dfs(int f,int fath) 18 { 19 depth[f]=depth[fath]+1; 20 fa[f][0]=fath; 21 22 for(int i=1;(1<<i)<=depth[f];i++) 23 fa[f][i]=fa[fa[f][i-1]][i-1]; //f的2^i祖先等于f的2^(i-1)祖先的2^(i-1)祖先 24 25 for(int i=head[f];i;i=way[i].next) 26 if(way[i].to!=fath) dfs(way[i].to,f); //遍历除爸爸外所有的儿砸 27 } 28 int lca(int x,int y) 29 { 30 if(depth[x]<depth[y]) swap(x,y); //设x的深度 >= y的深度 31 32 while(depth[x]>depth[y]) 33 x=fa[x][log2[depth[x]-depth[y]]-1]; //由于之前推log2多1 34 35 if(x==y) return x; // 如果y是x的祖先,那他们的LCA肯定就是y 36 37 for(int k=log2[depth[x]]-1;k>=0;k--) //不断向上跳 38 if(fa[x][k]!=fa[y][k]) x=fa[x][k],y=fa[y][k]; //跳到它们LCA的下面一层,如果不相等就跳过去 39 40 return fa[x][0]; 41 } 42 int main() 43 { 44 scanf("%d%d%d",&n,&m,&s); 45 for(int x,y,i=1;i<=n-1;i++) 46 { 47 scanf("%d%d",&x,&y); 48 add(x,y),add(y,x); 49 } 50 dfs(s,0); 51 for(int i=1;i<=n;i++) 52 log2[i]=log2[i/2]+1; //i/2自动整型(log2[i]=log2[i-1]+(1<<log2[i-1]==i);这样写更高大上) 53 for(int x,y,i=1;i<=m;i++) 54 { 55 scanf("%d%d",&x,&y); 56 printf("%d\n",lca(x,y)); 57 } 58 return 0; 59 }