LCA-Tarjan離線+鏈式前向星

LCA:最近公共祖先問題

解決方法:

       1. 採用鏈式前行星存圖,可以優化空間佔用和遍歷速度

       2. Tarjan離線可以一次性處理所有的請求,時間複雜度爲O(n+q)

 

下面簡單介紹下Tarjan離線求LCA:

      首先dfs遍歷樹,當某個結點左右子樹都遍歷完成後,處理所有與它有關的請求,然後將其利用並查集合併到父結點上。詳見圖解、

 

(1)

     

(2)

 

(3)

 

(4)

代碼(POJ 1330):

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<cmath>
  5 #include<algorithm>
  6 #include<queue>
  7 #include<stack>
  8 #include<deque>
  9 #include<map>
 10 #include<iostream>
 11 using namespace std;
 12 typedef long long  LL;
 13 const double pi=acos(-1.0);
 14 const double e=exp(1);
 15 const int N = 10100;
 16 
 17 #define lson i << 1, l, m
 18 #define rson i << 1 | 1, m + 1, r
 19 int cnt,ans;
 20 int a,b,n;
 21 int root;
 22 int head[N];    //指向結點i的第一條邊
 23 int is_root[N]; 
 24 int father[N];  // 並查集的boss結點
 25 int vis[N];
 26 
 27 struct edge
 28 {
 29     int to;
 30     int next;
 31 } edge[N];
 32 
 33 int seek(int ss)
 34 {
 35     int mid;
 36     int head = ss;
 37     while(ss != father[ss])
 38         ss = father[ss];
 39 
 40     while(head != ss)
 41     {
 42         mid = father[head];
 43         father[head] = ss;
 44         head = mid;
 45     }
 46     return ss;
 47 }
 48 
 49 void join(int xx, int yy)
 50 {
 51     int one = seek(xx);
 52     int two = seek(yy);
 53     if(one != two)
 54         father[two] = one;  //注意把誰變成誰的上級
 55 }
 56 
 57 void add(int x, int y)
 58 {
 59     edge[cnt].to = y;
 60     edge[cnt].next = head[x];
 61     head[x] = cnt++;
 62 }
 63 
 64 void init()
 65 {
 66     int i, p, j;
 67     int x, y;
 68     cnt = 0;
 69     memset(head, -1, sizeof(head));
 70     memset(is_root, 0, sizeof(is_root));
 71     memset(vis, 0, sizeof(vis));
 72     scanf("%d", &n);
 73     for(i = 0; i <= n; i++) //並查集預處理
 74         father[i] = i;
 75     for(i = 1; i < n; i++)
 76     {
 77         scanf("%d%d", &x, &y);
 78         add(x, y);            //加邊
 79         is_root[y] = 1;       
 80     }
 81     for(i = 1; i <= n; i++)
 82         if(is_root[i] == 0)
 83             root = i;
 84 }
 85 
 86 void LCA(int u)
 87 {
 88     int i, p, j;
 89     for(i = head[u]; i != -1; i = edge[i].next)
 90     {
 91         int v = edge[i].to;
 92         LCA(v);
 93         join(u, v);
 94         vis[v] = 1;
 95     }
 96 
 97     if(u == a && vis[b] == 1)
 98         ans = seek(b);
 99     if(u == b && vis[a] == 1)
100         ans = seek(a);
101 
102     return ;
103 }
104 
105 void solve()
106 {
107     scanf("%d%d", &a, &b);
108     LCA(root);
109 }
110 
111 int main()
112 {
113     int t, m, i, p, j;
114     scanf("%d", &t);
115     for(i = 1; i <= t; i++)
116     {
117         init();  // 鏈式前向星建圖
118         solve(); // Tarjan求LCA
119 
120         printf("%d\n", ans);
121     }
122     return 0;
123 }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章