Tarjan(离线)算法

  思路:

      1.任选一个点为根节点,从根节点开始。

      2.遍历该点u所有子节点v,并标记这些子节点v已被访问过。

      3.若是v还有子节点,返回2,否则下一步。

      4.合并v到u上。

      5.寻找与当前点u有询问关系的点v。

      6.若是v已经被访问过了,则可以确认u和v的最近公共祖先为v被合并到的父亲节点a。

 

1、POJ 1330 Nearest Common Ancestors

  题意:给出一颗有根树(外向树),再给出有向边。询问一次,求两点的最近公共祖先。

  思路:最最基础的LCA题目,而且只询问一次。对于外向树,记录入度,入度为0的则为根。

  ①tarjan离线算法实现

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<vector>
 4 #include<memory.h>
 5 using namespace std;
 6 const int maxn = 10010;
 7 const int maxq = 10;
 8 vector<int> node[maxn];//邻接表
 9 int q1, q2, ans;
10 int n, qnum;
11 int index[maxn];//入度
12 int pre[maxn];//并查集
13 bool vis[maxn];//标记是否访问过
14 pair<int, int>queq[maxq];//保存查询顺序
15 int f[maxn];//保存临时祖先
16 int Find(int x)
17 {
18     int r = x;
19     while (pre[r] != r)
20     {
21         r = pre[r];
22     }
23     int i = x, j;
24     while (i != r)
25     {
26         j = pre[i];
27         if (j != r) pre[i] = r;
28         i = j;
29     }
30     return r;
31 }
32 void Join(int root, int child)
33 {
34     int rx = Find(root), ry = Find(child);
35     if (rx != ry) pre[child] = root;
36 }
37 void LCA(int root)
38 {
39     f[Find(root)] = root;
40     vis[root] = true;//标记被访问过
41     int sz = node[root].size();
42     for (int i = 0; i < sz; i++)
43     {//访问所有root子节点
44         if (!vis[node[root][i]])
45         {
46             LCA(node[root][i]);//继续往下遍历
47             Join(root, node[root][i]);//合并
48             f[Find(root)] = root;
49         }
50     }
51     if (q1 == root&&vis[q2]) ans = f[Find(q2)];
52     else if (q2 == root&&vis[q1]) ans = f[Find(q1)];
53 }
54 void Init()//初始化
55 {
56     for (int i = 0; i <= n; i++)
57     {
58         node[i].clear();
59         pre[i] = i;
60     }
61     memset(vis, 0, sizeof(vis));
62     memset(f, 0, sizeof(f));
63     memset(index, 0, sizeof(index));
64 }
65 int main()
66 {
67     int t;
68     scanf("%d", &t);
69     while (t--)
70     {
71         scanf("%d", &n);
72         Init();
73         for (int i = 1; i <= n - 1; i++)
74         {
75             int u, v;
76             scanf("%d%d", &u, &v);
77             node[u].push_back(v);//有向图
78             index[v]++;
79         }
80         scanf("%d%d", &q1, &q2);
81         int root = 1;
82         for (; root <= n; root++) if (!index[root]) break;//入度为0的为根
83         LCA(root);
84         printf("%d", ans);
85         printf("\n");
86     }
87     return 0;
88 }
tarjan离线算法

相关文章:

  • 2021-12-07
  • 2022-02-03
  • 2021-07-19
  • 2022-12-23
猜你喜欢
  • 2021-11-30
  • 2021-05-23
  • 2021-10-17
  • 2022-01-21
  • 2021-11-03
相关资源
相似解决方案