ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

LCA-Tarjan离线+链式前向星

2021-02-01 09:01:45  阅读:160  来源: 互联网

标签:Tarjan 遍历 const 离线 LCA include 前向星


LCA:最近公共祖先问题

解决方法:

       1. 采用链式前行星存图,可以优化空间占用和遍历速度

       2. Tarjan离线可以一次性处理所有的请求,时间复杂度为O(n+q)

 

下面简单介绍下Tarjan离线求LCA:

      首先dfs遍历树,当某个结点左右子树都遍历完成后,处理所有与它有关的请求,然后将其利用并查集合并到父结点上。详见图解、

 

(1)

     

(2)

 

(3)

 

(4)

代码:

  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 }

 

标签:Tarjan,遍历,const,离线,LCA,include,前向星
来源: https://www.cnblogs.com/daybreaking/p/14355033.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有