题目描述
如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。
输入输出格式
输入格式:第一行包含三个正整数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。
1 #include<iostream> 2 #include<cstdio> 3 4 using namespace std; 5 6 const int N = 500100; 7 8 int n,m,root,ans,cnt; 9 int head[N]; 10 int deth[N]; 11 int f[N][30]; 12 bool vis[N]; 13 struct Edge{ 14 int to,nxt; 15 }e[N<<1]; 16 17 int Read() 18 { 19 int x=0,f=1; 20 char c=getchar(); 21 while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();} 22 while(c>='0'&&c<='9') {x=x*10+c-'0'; c=getchar();} 23 return x*f; 24 } 25 26 void add(int a,int b) 27 { 28 ++cnt; 29 e[cnt].to = b; 30 e[cnt].nxt = head[a]; 31 head[a] = cnt; 32 } 33 34 void dfs(int a) 35 { 36 vis[a] = true; 37 for(int i=1;i<=20;i++) 38 { 39 if(deth[a] < (1<<i)) break; 40 f[a][i] = f[f[a][i-1]][i-1]; 41 } 42 for(int i=head[a];i;i=e[i].nxt) 43 { 44 int now = e[i].to; 45 if(!vis[now]) 46 { 47 deth[now] = deth[a]+1; 48 f[now][0]=a; 49 dfs(now); 50 } 51 } 52 } 53 54 int lca(int u,int v) 55 { 56 if(deth[u] < deth[v])swap(u,v); 57 int d = deth[u] - deth[v]; 58 for (int i=0; i<25; i++) //值得注意的是,这里需要从零枚举 59 { 60 if ( (1<<i) & d)//一个判断,模拟一下就会很清晰 61 u = f[u][i]; 62 } 63 if (u==v) return u; 64 for (int i=25; i>=0; i--) 65 { 66 if (f[u][i]!=f[v][i]) //跳2^j步不一样,就跳,否则不跳 67 { 68 u = f[u][i]; 69 v = f[v][i]; 70 } 71 } 72 u = f[u][0]; //上述过程做完,两点都在LCA下一层,所以走一步即可 73 return u; 74 } 75 76 int main() 77 { 78 int x,y; 79 n=Read(); 80 m=Read(); 81 root=Read(); 82 for(int i=1;i<n;i++) 83 { 84 x=Read(); 85 y=Read(); 86 add(x,y); 87 add(y,x); 88 } 89 deth[root] = 1; 90 dfs(root); 91 while(m--) 92 { 93 x=Read(); 94 y=Read(); 95 printf("%d ",lca(x,y)); 96 } 97 return 0; 98 }