zoukankan      html  css  js  c++  java
  • dfs序 + RMQ = LCA

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

    如上图所示,则整个遍历过程为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 = %d
    " , 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 %d
    " , 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号节点为根)

  • 相关阅读:
    eclipse的安装
    第一章:Javascript语言核心
    jQuery理解之(二)功能函数
    jQuery理解之(一)动画与特效
    jQuery实现单击和鼠标感应事件。
    jQuery使用之(五)处理页面的事件
    jQuery使用之(四)处理页面的表单元素
    jQuery使用之(三)处理页面的元素
    jQuery使用之(二)设置元素的样式
    jQuery使用之(一)标记元素属性
  • 原文地址:https://www.cnblogs.com/get-an-AC-everyday/p/4673255.html
Copyright © 2011-2022 走看看