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 }
  • 相关阅读:
    关于virtualbox配置centos7的网络问题
    centos7在命令行下安装图形界面
    ajax后台返回指定的错误码
    h5前端animate等js特效问题汇总
    tp5中的input助手函数
    使网页滑动效果更加流畅
    关于vagrant环境下项目中图片缓存的问题
    h5图片预览功能
    微信jssdk遇到的一些问题汇总
    curl请求curl_exec返回false,curl_error返回空
  • 原文地址:https://www.cnblogs.com/Gster/p/4730921.html
Copyright © 2011-2022 走看看