1. 程式人生 > >樹鏈剖分求LCA

樹鏈剖分求LCA

bsp 兩個 pla str 空間 num isp gif 節點和

樹鏈剖分求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)。

在線算法。

樹鏈剖分求LCA