LCA---模板

LCA:最近公共祖先

性质:1、LCA( u ) = u。

           2、u 是 v 的祖先,当且仅当 LCA( u , v ) = u。

           3、如果 u 不为 v 的祖先并且 v 不为 u 的祖先,那么这两个点属于不同的子树。

           4、两点的最近公共祖先必定处在两点间的树上最短路上。

           5、d( u , v ) = h( u ) + h( v ) - 2*h( LCA( u , v )) ,其中 d 是树上两点间的最短距离, h 是该点与树根之间的距离。

用途:求树从 x 到 y 节点最短路径上所有节点的值之和。

代码:

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 #define MOD 1e9+7 
 4 #define INF 0x3f3f3f3f
 5 #define mem(a,x) memset(a,x,sizeof(a))  
 6 #define _for(i,a,b) for(int i=a; i< b; i++)
 7 #define _rep(i,a,b) for(int i=a; i<=b; i++)
 8 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
 9 
10 using namespace std;
11 const int MAXN = 1000005 ;
12 inline int rd() 
13 {
14     int res = 0,flag = 0;
15     char ch;
16     if ((ch = getchar()) == '-')flag = 1;
17     else if(ch >= '0' && ch <= '9')res = ch - '0';
18     while ((ch = getchar()) >= '0' && ch <= '9')res = (res<<1) + (res<<3) + (ch - '0');
19     return flag ? -res : res;
20 }
21 //
22 int head[MAXN]; 
23 int num=0;
24 struct edg{
25    int next,to;
26 }edge[MAXN];
27 void edge_add(int u,int v)   //链式前向星存图
28 {
29    num++;
30    edge[num].next=head[u];edge[num].to=v;head[u]=num;
31    edge[++num].next=head[v];edge[num].to=u;head[v]=num;
32 }
33 //---------------------
34 // lca部分
35 int n,m,s;
36 int dep[MAXN]={0},f[MAXN][23];
37 void dfs(int u,int father)//对应深搜预处理f数组 
38 {
39     dep[u]=dep[father]+1;
40     for(int i=1;(1<<i)<=dep[u];i++)
41     {
42         f[u][i]=f[f[u][i-1]][i-1];
43     }
44     for(int i=head[u];i;i=edge[i].next)
45     {
46         int v=edge[i].to;
47         if(v==father)continue;//双向图需要判断是不是父亲节点 
48         f[v][0]=u;
49         dfs(v,u);
50     }
51 }
52 int lca(int x,int y)
53 {
54     if(dep[x]<dep[y])swap(x,y);
55     for(int i=20;i>=0;i--)//从大到小枚举使x和y到了同一层 
56     {
57         if(dep[f[x][i]]>=dep[y])x=f[x][i];
58         if(x==y)return x;
59     }
60     for(int i=20;i>=0;i--)//从大到小枚举 
61     {
62         if(f[x][i]!=f[y][i])//尽可能接近 
63         {
64             x=f[x][i];y=f[y][i];
65         } 
66     } 
67     return f[x][0];//随便找一个**输出 
68 }
69 int main(){
70     scanf("%d%d%d",&n,&m,&s);
71     for(int i=1;i<n;i++)
72     {
73         scanf("%d",&a1);scanf("%d",&a2);
74         edge_add(a1,a2);//链式存边 
75     }
76     dfs(s,0);
77     for(int i=1;i<=m;i++)
78     {
79         scanf("%d %d",&a1,&a2);
80         printf("%d\n",lca(a1,a2));//求两个节点的LCA 
81     }
82     return 0;
83 } 
View Code

 

posted @ 2020-08-18 11:51  hachuochuo  阅读(152)  评论(0编辑  收藏  举报