zoukankan      html  css  js  c++  java
  • poj1330 lca 最近公共祖先问题学习笔记

    首先推荐两个博客网址:

    http://dongxicheng.org/structure/lca-rmq/

    http://scturtle.is-programmer.com/posts/30055.html

    [转]tarjan算法的步骤是(当dfs到节点u时):
    1 在并查集中建立仅有u的集合,设置该集合的祖先为u
    1 对u的每个孩子v:
       1.1 tarjan之
       1.2 合并v到父节点u的集合,确保集合的祖先是u
    2 设置u为已遍历
    3 处理关于u的查询,若查询(u,v)中的v已遍历过,则LCA(u,v)=v所在的集合的祖先
     
    举例说明(非证明):


    假设遍历完10的孩子,要处理关于10的请求了
    取根节点到当前正在遍历的节点的路径为关键路径,即1-3-8-10
    集合的祖先便是关键路径上距离集合最近的点
    比如此时:
        1,2,5,6为一个集合,祖先为1,集合中点和10的LCA为1
        3,7为一个集合,祖先为3,集合中点和10的LCA为3
        8,9,11为一个集合,祖先为8,集合中点和10的LCA为8
        10,12为一个集合,祖先为10,集合中点和10的LCA为10
    你看,集合的祖先便是LCA吧,所以第3步是正确的
    道理很简单,LCA(u,v)便是根至u的路径上到节点v最近的点

    为什么要用祖先而且每次合并集合后都要确保集合的祖先正确呢?
    因为集合是用并查集实现的,为了提高速度,当然要平衡加路径压缩了,所以合并后谁是根就不确定了,所以要始终保持集合的根的祖先是正确的
    关于查询和遍历孩子的顺序:
    wikipedia上就是上文中的顺序,很多人的代码也是这个顺序
    但是网上的很多讲解却是查询在前,遍历孩子在后,对比上文,会不会漏掉u和u的子孙之间的查询呢?
    不会的
    如果在刚dfs到u的时候就设置u为visited的话,本该回溯到u时解决的那些查询,在遍历孩子时就会解决掉了
    这个顺序问题就是导致我头大看了很久这个算法的原因,也是絮絮叨叨写了本文的原因,希望没有理解错= =

    对于这道题

    题意:求最近公共祖先lca

    下面是学来的tarjan代码

      1 #include <iostream>
      2 #include <algorithm>
      3 #include <cstdio>
      4 #include <cstdlib>
      5 #include <cstring>
      6 #include <cmath>
      7 #include <ctime>
      8 
      9 using namespace std;
     10 
     11 class Edge
     12 {
     13     public:
     14     int    to;
     15     int    next;
     16 }e[11000];
     17 
     18 int    n,T,cnt;
     19 int    f[11000],depth[11000],anc[11000],p[11000];
     20 bool    visited[11000],In[11000];
     21 
     22 inline    void    Add_edge(const int & x,const int & y)
     23 {
     24     e[++cnt].to=y;
     25     e[cnt].next=p[x];
     26     p[x]=cnt;
     27     return ;
     28 }
     29 
     30 inline    int    get_anc(const int &x)
     31 {
     32     return f[x]==x ? x:f[x]=get_anc(f[x]);
     33 }
     34 
     35 inline    void    Union(const int & x,const int & y)
     36 {
     37     int    S,T;
     38     S=get_anc(x);
     39     T=get_anc(y);
     40     if(S==T)return ;
     41     if(depth[S]<=depth[T])
     42         f[S]=T,depth[S]+=depth[T];
     43     else
     44         f[T]=S,depth[T]+=depth[S];
     45     return ;
     46 }
     47 
     48 void    Dfs(const int &S,const int d)
     49 {
     50     int    i;
     51     depth[S]=d;
     52     for(i=p[S];i;i=e[i].next)
     53     {
     54         Dfs(e[i].to,d+1);
     55     }
     56 
     57     return ;
     58 }
     59 
     60 int    Lca_tarjan(const int & s,const int & t,const int & u)
     61 {
     62     int    i,temp;
     63     
     64     anc[u]=u;
     65     for(i=p[u];i;i=e[i].next)
     66     {
     67         temp=Lca_tarjan(s,t,e[i].to);
     68         if(temp)return temp;
     69         Union(u,e[i].to);
     70         anc[get_anc(u)]=u;
     71     }
     72 
     73     visited[u]=true;
     74     if(s==u&&visited[t])
     75         return anc[get_anc(t)];
     76     if(t==u&&visited[s])
     77         return anc[get_anc(s)];
     78 
     79     return 0;
     80 }
     81 
     82 inline    void    Init()
     83 {
     84     cnt=0;
     85     memset(depth,0,sizeof(depth));
     86     memset(visited,0,sizeof(visited));
     87     memset(anc,0,sizeof(anc));
     88     memset(p,0,sizeof(p));
     89     memset(e,0,sizeof(e));
     90     memset(In,0,sizeof(In));
     91 
     92     for(int i=1;i<=n;++i)
     93     {
     94         f[i]=i;
     95     }
     96 
     97     return ;
     98 }
     99 
    100 int main()
    101 {
    102     //freopen("1330.in","r",stdin);
    103     
    104     int    i,x,y,s,t,S;
    105     
    106     scanf("%d",&T);
    107     while(T--)
    108     {
    109         scanf("%d",&n);
    110         Init();
    111         for(i=1;i<n;++i)
    112         {
    113             scanf("%d%d",&x,&y);
    114             Add_edge(x,y);
    115             In[y]=true;
    116         }
    117         
    118         for(S=1;S<=n;++S)
    119             if(!In[S])break;
    120 
    121         scanf("%d%d",&s,&t);
    122         Dfs(S,1);
    123         printf("%d
    ",Lca_tarjan(s,t,S));
    124     }
    125     
    126     return 0;
    127 }
  • 相关阅读:
    FJNU 1151 Fat Brother And Geometry(胖哥与几何)
    FJNU 1157 Fat Brother’s ruozhi magic(胖哥的弱智术)
    FJNU 1159 Fat Brother’s new way(胖哥的新姿势)
    HDU 3549 Flow Problem(最大流)
    HDU 1005 Number Sequence(数列)
    Tickets(基础DP)
    免费馅饼(基础DP)
    Super Jumping! Jumping! Jumping!(基础DP)
    Ignatius and the Princess IV(基础DP)
    Keywords Search(AC自动机)
  • 原文地址:https://www.cnblogs.com/Gster/p/4730921.html
Copyright © 2011-2022 走看看