dfs序 + RMQ = LCA

dfs序是指你用dfs遍历一棵树时,每个节点会按照遍历到的先后顺序得到一个序号。然后你用这些序号,可以把整个遍历过程表示出来。

dfs序 + RMQ = LCA

如上图所示,则整个遍历过程为1 2 3 2 4 5 4 6 4 2 1 7 8 7 1

反正按照实现目的不同,dfs序会长得不太一样,比如说为了实现LCA就需要上面形式的dfs序。

用vs[]来保存整个遍历过程。

id[i]用来保存i节点的序号第一次出现在vs[]中时的下标。

这样当询问u,v点的LCA是谁是,你只要找到在vs[id[u]<= i <= id[v]]中最小值即可,那个最小值所对应的节点就是u,v的LCA

而这个过程你可以用RMQ进行预处理,然后O(1)就可以得到。(你应该知道vs[]的总长度为n*2-1)

1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int M = 1e5 + 10 ;
 4 vector<int> g[M] ;
 5 int n ;
 6 
 7 vector<int> vs ;//dfs order
 8 int tot ;
 9 int orm[M] ;
10 int id[M] ;
11 int dep[M] ;
12 
13 int d[M][30] ;//RMQ
14 void dfs (int o , int u ,int  DEP) {
15         int tmp = tot ++ ;
16         dep[u] = DEP ;
17         id[u] = vs.size () ;
18         orm[tmp] = u ;
19         vs.push_back (tmp) ;
20 
21         for (int i = 0 ; i < g[u].size () ; i ++) {
22                 int v = g[u][i] ;
23                 if (v == o) continue ;
24                 dfs (u , v , DEP + 1) ;
25         }
26         int len = vs.size () ;
27         if (vs[len-1] == tmp) vs.push_back (vs[id[o]]) ;
28         else vs.push_back (tmp) ;
29 }
30         
31 void init_RMQ () {
32         for (int i = 0 ; i < 2*n-1 ; i ++) d[i][0] = vs[i] ;
33         for (int j = 1 ; (1 << j) <= n ; j ++) {
34                 for (int i = 0 ; i + (1 << j) <= n ; i ++) {
35                         d[i][j] = min (d[i][j-1] , d[i+(1<<(j-1))][j-1]) ;
36                 }
37         }
38 }
39 
40 int RMQ (int l , int r) {
41         printf ("l = %d , r = %dn" , l , r ) ;
42         int k = 0 ;
43         while ( (1<<(k+1)) <= r - l + 1) k ++ ;
44         int tmp = min (d[l][k] , d[1+r-(1<<k)][k]) ;
45         return orm[tmp] ;
46 }
47 void Print () {
48         for (int i = 0 ; i < 2*n-1 ; i ++) printf ("%3d " , i ) ; puts ("") ;
49         puts ("dfs order:") ;
50         for (int i = 0 ; i < 2*n-1 ; i ++) printf ("%3d " , vs[i]) ; puts ("") ;
51         puts ("deep:") ;
52         for (int i = 0 ; i < n ; i ++) printf ("%3d " , dep[i]) ; puts ("") ;
53         puts ("id :") ;
54         for (int i = 0 ; i < n ; i ++) printf ("%3d " , id[i]) ; puts ("") ;
55 }
56 
57 void LCA () {
58         dfs (0,0,0) ;
59         init_RMQ () ;
60         Print () ;
61 }
62 
63 int main () {
64         cin >> n ;
65         for (int i = 0 ; i < n - 1 ; i ++) {
66                int u , v ;
67                cin >> u >> v ;
68                g[u].push_back (v) ;
69                g[v].push_back (u) ;
70         }
71         LCA () ;
72         int Q ;
73         cin >> Q ;
74         while (Q --) {
75                 int u , v ;
76                 cin >> u >> v ;
77                 if (id[u] > id[v]) swap (u , v ) ;
78                 int ans = RMQ (id[u] , id[v]) ;
79                 printf ("The %d and %d the lastest ans is %d , and they are away from %dn" , u , v , ans , dep[u]+dep[v]-2*dep[ans]) ;
80         }
81         return 0 ;
82 }

测试数据:

8

0 1

0 2

1 3

1 4

2 5

4 6

4 7

3

0 4

3 4

6 2

3次询问的答案你画一下即可。hhhhhh(以0号节点为根)

原文链接: https://www.cnblogs.com/get-an-AC-everyday/p/4673255.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/219591

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月13日 上午10:36
下一篇 2023年2月13日 上午10:37

相关推荐