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 ",lca(a1,a2));//求两个节点的LCA 81 } 82 return 0; 83 }