[最近公共祖先]最近公共祖先(LCA)

题目描述

如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。

输入输出格式

输入格式:

第一行包含三个正整数N、M、S,分别表示树的结点个数、询问的个数和树根结点的序号。

接下来N-1行每行包含两个正整数x、y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树)。

接下来M行每行包含两个正整数a、b,表示询问a结点和b结点的最近公共祖先。

输出格式:

输出包含M行,每行包含一个正整数,依次为每一个询问的结果。

输入输出样例

输入样例#1: 复制
5 5 4
3 1
2 4
5 1
1 4
2 4
3 2
3 5
1 2
4 5
输出样例#1: 复制
4
4
1
4
4

说明

时空限制:1000ms,128M

数据规模:

对于30%的数据:N<=10,M<=10

对于70%的数据:N<=10000,M<=10000

对于100%的数据:N<=500000,M<=500000

样例说明:

该树结构如下:

第一次询问:2、4的最近公共祖先,故为4。

第二次询问:3、2的最近公共祖先,故为4。

第三次询问:3、5的最近公共祖先,故为1。

第四次询问:1、2的最近公共祖先,故为4。

第五次询问:4、5的最近公共祖先,故为4。

故输出依次为4、4、1、4、4。

先存下板子,之后再写一篇LCA的学习笔记

 1 #include <iostream>
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4 const int N = 5e5+50;
 5 int n,m,s;
 6 int head[N],dep[N],p[N][22];
 7 int lg[N];
 8 struct node{
 9     int to,net;
10 };
11 node edge[N*2];
12 int cnt=0;
13 void add(int u,int v){
14     edge[++cnt].to=v;
15     edge[cnt].net=head[u];
16     head[u]=cnt;
17 }
18 void init(){
19     for(register int i=1;i<=n;i++){
20         lg[i]=lg[i-1]+(1<<lg[i-1]==i);
21     }
22 }
23 void dfs(int u,int fa){
24     dep[u]=dep[fa]+1;
25     p[u][0]=fa;
26     for(register int i=1;(1<<i)<=dep[u];i++){
27         p[u][i]=p[p[u][i-1]][i-1];
28     }
29     for(register int i=head[u];i;i=edge[i].net){
30         if(edge[i].to==fa)
31             continue;
32         dfs(edge[i].to,u);
33     }
34 }
35 int lca(int x,int y){
36     if(dep[x]<dep[y]){
37         swap(x,y);
38     }
39     while(dep[x]>dep[y]){
40         x=p[x][lg[dep[x]-dep[y]]-1];
41     }
42     if(x==y)
43         return x;
44     for(register int k=lg[dep[x]];k>=0;k--){
45         if(p[x][k]!=p[y][k]){
46             x=p[x][k];
47             y=p[y][k];
48         }
49     }
50     return p[x][0];
51 }
52 int main()
53 {
54     memset(head,-1,sizeof(head));
55     scanf("%d%d%d",&n,&m,&s);
56     for(register int i=1;i<n;i++){
57         int x,y;
58         scanf("%d %d",&x,&y);
59         add(x,y);
60         add(y,x);
61     }
62     init();
63     dfs(s,0);
64     for(register int i=1;i<=m;i++){
65         int a,b;
66         scanf("%d %d",&a,&b);
67         int ans=lca(a,b);
68         printf("%d
",ans);
69     }
70     //cout << "Hello world!" << endl;
71     return 0;
72 }
View Code
原文地址:https://www.cnblogs.com/SoulSecret/p/9698501.html