树链剖分求LCA

树链剖分求LCA

树链剖分需要将树的边分为重边和轻边。每个节点和他的儿子之间只能有一条重边,连接着该节点与他儿子中子树节点最大的一个。一系列连续起来的重边叫做重链,重链上的每个点的top值都是重链的顶端节点。

用树链剖分来求LCA,就需要每次比较top_x与top_y的深度,将深度较大的点变为top_x的父节点。直到top_x=top_y,循环结束。两者之中深度较小的节点,就是这两个点的LCA。

下附代码:

 1 #include<cstdio>
 2 #include<iostream>
 3 #define N 42000
 4 using namespace std;
 5 int next[N],to[N],num,head[N],size[N],deep[N],father[N],top[N],n,m,p,a,b;
 6 void add(int false_from,int false_to){
 7     next[++num]=head[false_from];
 8     to[num]=false_to;
 9     head[false_from]=num;
10 }
11 void dfs1(int x){
12     size[x]=1;
13     deep[x]=deep[father[x]]+1;
14     for(int i=head[x];i;i=next[i])
15         if(father[x]!=to[i]){
16             father[to[i]]=x;
17             dfs1(to[i]);
18             size[x]+=size[to[i]];
19         }
20 }
21 void dfs2(int x){
22     int mmax=0;
23     if(!top[x])
24         top[x]=x;
25     for(int i=head[x];i;i=next[i])
26         if(father[x]!=to[i]&&size[to[i]]>size[mmax])
27             mmax=to[i];
28     if(mmax){
29         top[mmax]=top[x];
30         dfs2(mmax);
31     }
32     for(int i=head[x];i;i=next[i])
33         if(to[i]!=mmax&&father[x]!=to[i])
34             dfs2(to[i]);
35 }
36 int lca(int x,int y){
37     while(top[x]!=top[y]){
38         if(deep[top[x]]<deep[top[y]])
39             swap(x,y);
40         x=father[top[x]];
41     }
42     if(deep[x]<deep[y])
43         return x;
44     return y;
45 }
46 int main(){
47     scanf("%d%d%d",&n,&m,&p);
48     for(int i=1;i<n;++i){
49         scanf("%d%d",&a,&b);
50         add(a,b);
51         add(b,a);
52     }
53     dfs1(p);
54     dfs2(p);
55     for(int i=1;i<=m;++i){
56         scanf("%d%d",&a,&b);
57         printf("%d ",lca(a,b));
58     }
59     return 0;
60 }
View Code

 预处理复杂度:O(n)。

一组询问复杂度:O(logn)。

空间复杂度:O(n)。

在线算法。

原文地址:https://www.cnblogs.com/jsawz/p/6814938.html