【lca】【tarjan】【模板】POJ1330模板题

  这是我第一篇博客,写的肯定有点丑,轻喷(如果有人看的话。)

  我们先搞懂tarjan lca算法的原理,

  首先建树和记录询问信息(我看网上的代码大都由vector来完成),之后dfs这棵树,遍历树的时候,每个节点最初是没有标记的,当他以及他的所有子节点都已经被遍历后做上标记,回溯的时候,再把它加入到它父节点的集合里,这里用并查集来完成。这样的话,假定我们已经遍历了询问列表中(u,v)的u,当我们遍历到v时,由于dfs的特性,它们的最近公共祖先必然被访问过并且标记过,而u已经属于最近公共祖先的集合了,所以直接输出fa[u]即可,也许有点童鞋会问,为什么一定是最近的呢?为什么不会输出根节点呢?因为这时我们还没有完整遍历这棵子树(也就是以最近公共祖先为根节点的子树),还不会回溯到最近公共祖先的父节点,fa[最近公共祖先]还没有加入的父节点的集合里,所以输出结果一定是最近的。

  遍历整棵树需要祭出O(n)的复杂度,完成查询需要祭出O(m)的复杂度,整个算法的复杂度是O(n+m),非常的高效,而且代码也容易敲出来。

  以下是代码,借鉴了http://blog.csdn.net/lanshui_yang/article/details/11746513,做了一些小小的修改。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<vector>
 6 using namespace std;
 7 const int maxn=10000+10;
 8 vector<int > son[maxn];//儿子
 9 int fa[maxn];//并查集 
10 int fas[maxn];//父节点个数 
11 int root;//保存树的根节点 
12 bool vis[maxn];//Cheak访问标记 
13 int n;
14 int u,v;//保存要查询的两点 
15 int find(int x)
16 {
17     if(fa[x]==x) return x;
18     return fa[x]=find(fa[x]);
19 }
20 void init()
21 {
22     memset(vis,0,sizeof(vis));
23     for(int i=1;i<=n;i++) fa[i]=i;
24     for(int i=0;i<=n;i++)
25     {
26         son[i].clear();
27     }
28 }
29 void read()
30 {
31     cin>>n;
32     init();
33     for(int i=0;i<n-1;i++)
34     {
35         int a,b;
36         scanf("%d%d",&a,&b);
37         son[a].push_back(b);
38         vis[b]=true;//这里借用vis,把有入度的点标记出来 
39     }
40     cin>>u>>v;
41     for(int i=1;i<=n;i++)
42     {
43         if(!vis[i])//没有入度的,为树的根节点 
44         {
45             root=i;
46             break;
47         }
48     }
49     memset(vis,0,sizeof(vis));//在read函数里的vis已经完成了任务,清零
50 }
51 void tarjan_lca(int root)
52 {
53     vis[root]=true;
54     for(int i=0;i<son[root].size();i++)//遍历所有子树 
55     {
56         int y=son[root][i];
57         if(!vis[y])
58         {
59             if(y==u && vis[v])//两个请求的节点都已经处理过
60             {
61                 printf("%d\n",find(v));
62                 return;
63             }
64             if(y==v && vis[u])
65             {
66                 printf("%d\n",find(u));
67                 return;
68             }
69             tarjan_lca(y);
70             fa[y]=root;
71         }
72     }
73 }
74 int main()
75 {
76     int cas;
77     cin>>cas;
78     for(int i=1;i<=cas;i++)
79     {
80         read();
81         tarjan_lca(root);
82     }
83     return 0;
84 }

 

posted @ 2015-07-28 22:20  sajuuk  阅读(403)  评论(0编辑  收藏  举报