树链剖分求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 }
预处理复杂度:O(n)。
一组询问复杂度:O(logn)。
空间复杂度:O(n)。
在线算法。