• hdu--2586--lca_tarjan<证明tarjan这个人很流弊>


    开篇 敬仰下 大师-tarjan 发明的这些算法太流弊了=-=使用这个lca_tarjan之前 可以先去学习下使用tarjan解决scc强连通问题

    我本来是去做到hdu-4912-发现做不来=-= 去网上搜了下 都说是神马lca的....那就去学下吧 而且很多也将这题当做入门题..

    lca分离线和在线 这边我介绍的是离线算法 是要先将所有的询问一起处理 而不是单个单个地去处理  处理完成之后 你自己选择一种方式将答案存储下来

    然后再进行一遍输出答案

    我再网上没有找到一篇好的博客来推荐给大家 所以这边我就不写 传送门的故事了 -.-

    学习下它 对于你的思想 是很有帮助的 很多时候 都是这样

    这边我们需要用到 并查集来优化这个算法

    我们结合下图 进行分析

    现在 我们以上图为例 建立的边<无向>

    1<-->2   2<-->3   2<--->4   3<--->5   5<--->7   2<--->4  4<--->6  1<--->8  8<--->9

    我们的询问就是

    lca:<2,3>  ,   <5,6>    ,    <7,4>      ,    <9,3>

    这4组查询结果也算都是有一些特点的吧  虽然我们很容易地可以从上图中得到结果

    2 3肯定是2啊 因为3是2的子树下的结点

    5 6就是2了 他们同时是2的子树的结点 你也当然会说他们也是1的子树的结点啊 但是2的深度更大 离根结点更远

    还有2个就先不说了.....

    既然 这是树 那我们解决的时候首先就自己确定一个根结点 按习惯上 我们都喜欢默认1当做根结点 当然你也可以2 3 ……n

    草。。我突然发现 不会分析下去了..

    就是要注意下 假设你当前访问到的结点是u 现在有一个结点是v与u相邻 那么假如v没有被访问过 那就再lca_tarjan(v)即去访问v 这边的后续操作要明白 既然u与v相邻 那我们可以将他们看成是在同一棵子树上的 所以我们将v所在的集合并在u所在的集合之下 这时 就需要用到并查集了 

    很多人会习x = find(u)  y = find(v) father[y] = x;

    但其实 我觉得 直接father[v] = u就足够了 因为你find的结果肯定是自身结点 如若不是 那就是成环了 这样本来就不可以使用tarjan去解决了

    //我也不确定上面我的理解是否正确 如若错误 一定要告诉我啊...

    当然 在我们接下去询问求u v的lca的时候 是一定要用 find(v)的 因为v是比u先遍历到的 离根结点更近 因为可能会出现如 上图询问《5,6>这样的情况 这时候 father[5]=3 这是没有错的 但<5,6>的lca就是2了 所以我们这边必须是要find(v)的 就是用来针对这种情况 假如这棵子树的根结点是A 假设只有B C与它相连 而我们是询问B C这2棵子树下的lca 而我们递归回溯过来更新father[]是更新到直接与它相邻的为止 so 需要进行find操作 在2棵不同的子树情况下

    这边最好去理解下 子树的概念 这在数据结构有涉及到 这个可以是递归定义的

    可能有些 言不达意 =-= 都是自我理解 大家可以多参考一些博客 然后自己模拟画画 就是了

      1 #include <iostream>
      2 #include <cstring>
      3 using namespace std;
      4 
      5 int cnt1 , cnt2;
      6 const int size1 = 40010;
      7 const int size2 = 210;
      8 struct graph
      9 {
     10     int from;
     11     int to;
     12     int val;
     13     int next;
     14     int lca;
     15 };
     16 graph edge[size1*2];
     17 int Ehead[size1];
     18 graph node[size2*2];
     19 int Nhead[size1];
     20 bool vis[size1];
     21 int dist[size1];
     22 int father[size1];
     23 
     24 void init( )
     25 {
     26     memset( Ehead , -1 , sizeof(Ehead) );
     27     memset( Nhead , -1 , sizeof(Nhead) );
     28     memset( dist , 0 , sizeof(dist) );
     29     memset( vis , false , sizeof(vis) );
     30 }
     31 
     32 int find( int x )
     33 {
     34     return x == father[x] ? x : father[x] = find( father[x] );
     35 }
     36 
     37 
     38 void addEdge( int from , int to , int val )
     39 {
     40     edge[cnt1].to = to;
     41     edge[cnt1].val = val;
     42     edge[cnt1].next = Ehead[from];
     43     Ehead[from] = cnt1 ++;
     44 }
     45 
     46 void addQueryEdge( int from , int to )
     47 {
     48     node[cnt2].from = from;
     49     node[cnt2].to = to;
     50     node[cnt2].next = Nhead[from];
     51     Nhead[from] = cnt2 ++;
     52 }
     53 
     54 void lca_tarjan( int u , int val )
     55 {
     56     int v , x , y;
     57     vis[u] = true;
     58     dist[u] = val;
     59     father[u] = u;
     60     for( int i = Ehead[u] ; ~i ; i = edge[i].next )
     61     {
     62         v = edge[i].to;
     63         if( !vis[v] )
     64         {
     65             lca_tarjan( v , edge[i].val + val );
     66             x = find(u);
     67             y = find(v);
     68             if( x!=y )
     69             {
     70                 father[y] = x;
     71             }
     72         }
     73     }
     74     for( int i = Nhead[u] ; ~i ; i = node[i].next )
     75     {
     76         v = node[i].to; 
     77         if( vis[v] )
     78         {
     79             node[i].lca = node[i^1].lca = find(v);
     80         }
     81     }
     82 }
     83 
     84 int main()
     85 {
     86     cin.sync_with_stdio(false);
     87     int t , from , to , val , ans , id;
     88     int n , m;
     89     cin >> t;
     90     while( t-- )
     91     {
     92         init( );
     93         cin >> n >> m;
     94         cnt1 = cnt2 = 0;
     95         for( int i = 1 ; i<n ; i++ )
     96         {
     97             cin >> from >> to >> val;
     98             addEdge( from , to , val );
     99             addEdge( to , from , val );
    100         }
    101         for( int i = 0 ; i<m ; i++ )
    102         {
    103             cin >> from >> to;
    104             addQueryEdge( from , to );
    105             addQueryEdge( to , from );
    106         }
    107         lca_tarjan( 1 , 0 );
    108         for( int i = 0 ; i<m ; i++ )
    109         {
    110             id = i * 2;
    111             ans = dist[ node[id].from ] + dist[ node[id].to ] - 2*dist[ node[id].lca ];
    112             cout << ans << endl;
    113         }
    114     }
    115     return 0;
    116 }
    View Code

    忘了一个很重要的...lca是基于 无向无环图的 也可以说多叉树吧 我是觉得差不多的

    today:

      我们最大的敌人就是自己

      我们的恐惧来源于对自己的否定

      信心才是最重要的

    just follow your heart
  • 相关阅读:
    作业II
    7.26 tar命令
    7.24
    网络003
    网络002
    网络001
    MySQL基于amoeba读写分离实验
    MYSQL数据库之主从复制及读写分离
    MySQL的主从异步复制实验
    MYSQL数据库扩展 索引与事务与引擎
  • 原文地址:https://www.cnblogs.com/radical/p/3945072.html
Copyright © 2020-2023  润新知