1. 程式人生 > >倍增 Tarjan 求LCA

倍增 Tarjan 求LCA

                                                                                                                                                         ----程式碼都是  HDU 2586  "How far away" 為例


    倍增求LCA

 

  樹上倍增法。

  設F[x,k] 表示x的2的k次方輩祖先,即 由x向上走2的k次方到達的節點

  F[x,k]=F[F[x][k-1],k-1]

 

   預處理: 這類似於一個動態規劃的過程,階段就是節點的深度,因此,我們可以對樹進行bfs,按照層次順序,下節點入隊之前,計算它在F陣列中相應的值。

  基於F陣列計算LCA:

  1.設d[x]表示x的深度。不妨設d[x]>d[y]

  2.用二進位制拆分思想,把x上調到與y同一深度

  3.若x=y則LCA=y

     否則 把x,y同時向上調整,並保持深度一致且二者不相會。

    具體來說,就是依次嘗試把x,y同時向上走2的整數次方步(遞減),在每此嘗試中,若F[x,k]!=F[y,k],則令x=F[x,k],y=F[y,k]

  4.此時x,y必定只差一步就相會了 則 LCA=fa[x] (x的父結點)

                                                                                                                                                               -----《演算法競賽》

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<vector>
 4 #include<cmath>
 5 #define M 40010
 6 #define go(i,a,b) for(register int i=a;i<=b;i++)
 7 #define go1(i,a,b) for(register int i=a;i>=b;i--)
 8 using namespace std;
 9 int read()
10 {
11   int x=0,y=1; char c; c=getchar();
12   while(c<'0'||c>'9') {if(c=='-') y=-1;c=getchar();}
13   while(c>='0'&&c<='9') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
14   return x*y;
15 }
16 int b[M],d[M],f[M][30],dis[M],T,m,n,tt,t;
17 struct node1 {int v,w,n;} a[M*2];
18 void add(int u,int v,int w) {a[++tt].n=b[u];a[tt].v=v;a[tt].w=w;b[u]=tt;}
19 void dfs(int u)
20 {
21   int v,w;
22   for(int i=b[u];i;i=a[i].n)
23     {
24       v=a[i].v;w=a[i].w;
25       if(v==f[u][0]) continue ;
26       f[v][0]=u;
27       dis[v]=dis[u]+w;
28       d[v]=d[u]+1;
29       go(j,1,t) f[v][j]=f[f[v][j-1]][j-1];
30       dfs(v);
31     }
32 }
33 int lca(int u,int v)
34 {
35   if(d[u]>d[v]) swap(u,v);
36   go1(i,t,0) if(d[f[v][i]]>=d[u]) v=f[v][i];
37   if(u==v) return u;
38   go1(i,t,1) if(f[u][i]!=f[v][i]) {u=f[u][i];v=f[v][i];}
39   return f[u][0];
40 }
41 int main()
42 {
43   T=read();
44   while(T--)
45     {
46       int u,v,w;
47       n=read();m=read();t=(int)(log(n)/log(2))+1;
48       tt=0; go(i,1,n) {dis[i]=0;d[i]=0;b[i]=0;}
49       go(i,1,n-1) {u=read();v=read();w=read();add(u,v,w);add(v,u,w);}
50       d[1]=1;dfs(1);
51       go(i,1,m)
52     {u=read();v=read();printf("%d\n",dis[u]+dis[v]-2*dis[lca(u,v)]);}
53     }
54   return 0;
55 }
View Code

 

 

 Tarjan求LCA

 

演算法本質是使用並查集對“向上標記法”的優化。離線演算法。複雜度為O(m+n)。

                                                                                                                                                               -----《演算法競賽》

    畫圖非常清晰明瞭啊

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<vector>
 4 #define M 40010
 5 #define go(i,a,b) for(register int i=a;i<=b;i++)
 6 using namespace std;
 7 int read()
 8 {
 9   int x=0,y=1; char c; c=getchar();
10   while(c<'0'||c>'9') {if(c=='-') y=-1;c=getchar();}
11   while(c>='0'&&c<='9') {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
12   return x*y;
13 }
14 vector<int> q[M][2];
15 int b[M],ans[M],dis[M],f[M],fa[M];
16 int tt,n,m,T;
17 struct node1 {int v,w,n;} a[M*2];
18 void add(int u,int v,int w) {a[++tt].n=b[u];a[tt].v=v;a[tt].w=w;b[u]=tt;}
19 int find(int x) {if(fa[x]==x) return x; return fa[x]=find(fa[x]);}
20 void tarjan(int u)
21 {
22   f[u]=1;int v,w,id;
23   for(int i=b[u];i;i=a[i].n)
24     {
25       v=a[i].v;w=a[i].w;
26       if(f[v]) continue ;
27       dis[v]=dis[u]+w;
28       tarjan(v);
29       fa[v]=u;
30     }
31   for(int i=0;i<q[u][0].size();i++)
32     {
33       v=q[u][0][i];id=q[u][1][i];
34       if(f[v]==2)
35     {ans[id]=dis[u]+dis[v]-2*dis[find(v)];}
36     }
37   f[u]=2;
38 }
39 void init()
40 {
41   tt=0;
42   go(i,1,n)
43     {
44       fa[i]=i;q[i][1].clear();q[i][2].clear();dis[i]=0;f[i]=0;b[i]=0;
45     }
46 }
47 int main()
48 {
49   T=read();
50   while(T--)
51     {
52       n=read();m=read();  int u,v,w;
53       init();;
54       go(i,1,n-1)
55     {u=read();v=read();w=read();add(u,v,w);add(v,u,w);}
56       go(i,1,m)
57     {
58       u=read();v=read();
59       q[u][0].push_back(v);q[v][0].push_back(u);
60       q[u][1].push_back(i);q[v][1].push_back(i);
61     }
62       tarjan(1);
63       go(i,1,m) printf("%d\n",ans[i]);
64     }
65   return 0;
66 }
View Code