[最近公共祖先(LCA)]

首先这个题 很毒瘤 被数据卡了 很长时间

题目描述

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

输入输出格式

输入格式:

 

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

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

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

 

输出格式:

 

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

解析

结构体 来存  邻接表

d数组表示 这个点 的 深度

f 数组 表示 i 向上跳 2^k 步的点 

CODE:

 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 int n,m,s,num;
 5 int d[500001],f[21][500001];
 6 int lin[1000001];
 7 struct qwq{
 8     int to,next;
 9 }zh[10000001];
10 void add(int x,int y)//邻接表 存 图 
11 {
12     num++;
13     zh[num].to=y;// x 能到达的点 
14     zh[num].next=lin[x];
15     lin[x]=num; 
16 }
17 void dfs(int x,int y)
18 {
19     d[x]=d[y]+1;
20     f[0][x]=y;
21     for(int k=1;d[x]>=(1<<k);k++)// 限制条件是 不能跳出这个 树 
22         f[k][x]=f[k-1][f[k-1][x]];//f表示i向上跳2^k步的点 
23     for(int i=lin[x];i;i=zh[i].next)
24       if(zh[i].to!=y)
25         dfs(zh[i].to,x);
26 }
27 int LCA(int u,int v)
28 {
29     if(d[u]<d[v])//d表示这个点的深度 
30     swap(u,v);
31     for(int k=20;k>=0;k--)
32     {
33         if(d[f[k][u]]>=d[v])// 不能跳的超过v 
34         u=f[k][u];
35     }
36     if(u==v)
37     return u;
38     for(int k=20;k>=0;k--)
39     {
40         if(f[k][u]!=f[k][v])// 公共点不能和跳到同样高的点,不然无法区分 这是不是最近的 
41         u=f[k][u],v=f[k][v];
42     }
43     return f[0][u];
44 } 
45 int main()
46 {
47     scanf("%d%d%d",&n,&m,&s);
48     for(int i=1;i<n;i++)
49     {
50         int x,y;
51         scanf("%d%d",&x,&y);
52         add(x,y),add(y,x); // 双向边 
53     }
54     dfs(s,0);
55     for(int i=1;i<=m;i++)
56     {
57         int x,y;
58         scanf("%d%d",&x,&y);
59         printf("%d\n",LCA(x,y));
60     }
61     return 0;
62 }

 

posted @ 2019-01-31 20:55  风丨铃  阅读(207)  评论(0编辑  收藏  举报