zoukankan      html  css  js  c++  java
  • 简单的LCA

      这么久了才做LCA的题,以前是感觉很难不敢去尝试,现在学习了一番之后发现算法本身并不难。。。。

      学习时看了这篇博文:https://www.cnblogs.com/JVxie/p/4854719.html, 我觉得实现的过程最重要,就把博文中Tarjan算法实现的方法以及伪代码贴到下面:

             Tarjan算法的基本思路:

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

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

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

          4.合并v到u上。

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

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

        遍历的话需要用到dfs来遍历,至于合并,最优化的方式就是利用并查集来合并两个节点。

        下面上伪代码:

    Tarjan(u)//marge和find为并查集合并函数和查找函数
    {
        for each(u,v)    //访问所有u子节点v
        {
            Tarjan(v);        //继续往下遍历
            marge(u,v);    //合并v到u上
            标记v被访问过;
        }
        for each(u,e)    //访问所有和u有询问关系的e
        {
            如果e被访问过;
            u,e的最近公共祖先为find(e);
        }
    }

        算法的运用以及实现过程的举例,博文中讲的很详细,我想补充一下我对Tarjan算法的理解,

      当程序在dfs过程中遍历到某个节点 N 时, 以 N 节点为根节点搜索它的子节点,在它的某一子节点或某一子树都遍历过后,遍历过的点的父节点都会变成节点 N。那么假设N的子树中 i 节点被遍历了,其父节点变成N ; 遍历到其他子节点 j 时, 若恰好存在询问 i , j ,且 i , j 都在以 N 为根的树内,那么就可以直接得到 i, j 的LCA为 N 节点。那么在一次dfs过程中就都得到了所有询问的LCA

    以下是两道例题的AC代码:

    CODEVS 2370 小机房的树

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<vector> 
     5 using namespace std;
     6 const int MAXN=75005;
     7 struct Edge{
     8     int to;
     9     int cost;
    10     int id;
    11 };
    12 vector<Edge> vec[MAXN];
    13 vector<Edge> Q[MAXN];
    14 bool vis[MAXN];
    15 int p[MAXN], res[MAXN];
    16 long long d[MAXN], resd[MAXN];
    17 void add_edge(int u, int v, int c){
    18     vec[u].push_back((Edge){v, c, -1});
    19     vec[v].push_back((Edge){u, c, -1});
    20 }
    21 void add_query(int a, int b, int id){
    22     Q[a].push_back((Edge){b, 0, id});
    23     Q[b].push_back((Edge){a, 0, id});
    24 }
    25 int find(int x){
    26     return (p[x]==x)?x:(p[x]=find(p[x]));
    27 }
    28 void Union(int x, int y)
    29 {
    30     x=find(x);
    31     y=find(y);
    32     if(x==y) return;
    33     else p[x]=y;
    34 }
    35 void tarjan(int now, int fa)
    36 {
    37     for(int i=0;i<vec[now].size();i++){
    38         Edge e=vec[now][i];
    39         if(!vis[e.to]&&e.to!=fa){
    40             /**/
    41             d[e.to]=d[now]+e.cost; 
    42             /**/ 
    43             tarjan(e.to, now);
    44             Union(e.to, now);//注意now 和 e.to 的顺序
    45             
    46         } 
    47     }
    48     for(int i=0;i<Q[now].size();i++){
    49         Edge e=Q[now][i];
    50         if(vis[e.to]){
    51             res[e.id]=find(e.to);
    52             resd[e.id]=d[e.to]+d[now]-2*d[res[e.id]];
    53         }
    54     }
    55     vis[now]=1;
    56 }
    57 int main()
    58 {
    59     int n,m,a,b,c;
    60     while(~scanf("%d", &n))
    61     {
    62         for(int i=0;i<=n;i++) p[i]=i;
    63         for(int i=0;i<n-1;i++){
    64             scanf("%d %d %d", &a, &b, &c);
    65             add_edge(a, b, c);
    66         }
    67         scanf("%d", &m);
    68         for(int i=0;i<m;i++){
    69             scanf("%d %d", &a, &b);
    70             add_query(a, b, i);
    71         }
    72         
    73         memset(vis, 0, sizeof(vis));
    74         memset(d, 0, sizeof(d));
    75         tarjan(0, -1);
    76         for(int i=0;i<m;i++){
    77             printf("%lld
    ", resd[i]);
    78         }
    79     }
    80 } 
    81 /*
    82 9
    83 1 2 0
    84 1 3 0
    85 2 4 0
    86 2 5 0
    87 3 6 0
    88 5 7 0
    89 5 8 0
    90 7 9 0
    91 4
    92 9 8
    93 4 6
    94 7 5
    95 5 3
    96 */
    View Code

    CODEVS 1036 商务旅行

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<vector> 
     5 using namespace std;
     6 const int MAXN=75005;
     7 struct Edge{
     8     int to;
     9     int cost;
    10     int id;
    11 };
    12 vector<Edge> vec[MAXN];
    13 vector<Edge> Q[MAXN];
    14 bool vis[MAXN];
    15 int p[MAXN], res[MAXN];
    16 long long d[MAXN], resd[MAXN];
    17 void add_edge(int u, int v, int c){
    18     vec[u].push_back((Edge){v, c, -1});
    19     vec[v].push_back((Edge){u, c, -1});
    20 }
    21 void add_query(int a, int b, int id){
    22     Q[a].push_back((Edge){b, 0, id});
    23     Q[b].push_back((Edge){a, 0, id});
    24 }
    25 int find(int x){
    26     return (p[x]==x)?x:(p[x]=find(p[x]));
    27 }
    28 void Union(int x, int y)
    29 {
    30     x=find(x);
    31     y=find(y);
    32     if(x==y) return;
    33     else p[x]=y;
    34 }
    35 void tarjan(int now, int fa)
    36 {
    37     for(int i=0;i<vec[now].size();i++){
    38         Edge e=vec[now][i];
    39         if(!vis[e.to]&&e.to!=fa){
    40             /**/
    41             d[e.to]=d[now]+e.cost; 
    42             /**/ 
    43             tarjan(e.to, now);
    44             Union(e.to, now);//注意now 和 e.to 的顺序
    45             
    46         } 
    47     }
    48     for(int i=0;i<Q[now].size();i++){
    49         Edge e=Q[now][i];
    50         if(vis[e.to]){
    51             res[e.id]=find(e.to);
    52             resd[e.id]=d[e.to]+d[now]-2*d[res[e.id]];
    53         }
    54     }
    55     vis[now]=1;
    56 }
    57 int main()
    58 {
    59     int n,m,a,b,c;
    60     while(~scanf("%d", &n))
    61     {
    62         for(int i=0;i<=n;i++) p[i]=i;
    63         for(int i=0;i<n-1;i++){
    64             scanf("%d %d", &a, &b);
    65             add_edge(a, b, 1);
    66         }
    67         scanf("%d", &m);
    68         scanf("%d", &a);
    69         for(int i=1;i<m;i++){
    70             scanf("%d", &b);
    71             add_query(a, b, i);
    72             a=b;
    73         }
    74         
    75         memset(vis, 0, sizeof(vis));
    76         memset(d, 0, sizeof(d));
    77         tarjan(1, -1);
    78         long long ans=0;
    79         for(int i=1;i<m;i++){
    80             ans+=resd[i];
    81         }
    82         printf("%lld
    ", ans);
    83     }
    84 } 
    View Code
  • 相关阅读:
    题解——栈(卡特兰递归数的应用)
    题解——主的赦免(递归的进一步理解)
    sql开窗函数 row_number () over(order by id )
    c# resources
    Fillder 转载
    用javascript实现控制打开网页窗口的大小 和HTML如何关闭窗口的技巧大全
    datatable 与dataview的区别
    Asp.net中DataBinder.Eval用法的总结
    FrameSet左右收缩编码
    ajax get post
  • 原文地址:https://www.cnblogs.com/MasterSpark/p/7848054.html
Copyright © 2011-2022 走看看