procedure2012
It's not worth it to know you're not worth it!

[关键字]:LCA

[题目大意]:求出两点间的最近公共祖先。

//=====================================================================================================

[分析]:利用并查集在每次对子树进行遍历时进行合并,因为对以x为根的子树的遍历时只有当x的所有子树都遍历过后才会把它合并到他父亲的集合里,所以当需要查找的两个节点q1、q2中q1已被遍历且q2正是当前遍历的节点时说明此时只有距他们最近的祖先是在集合里的(可能为q1或q2),所以只要找到已被遍历的q1所在集合的祖先就是这两的节点的LCA。POJ1470和此题是一样的只是询问变成了多组。

[代码]:

View Code
 1 #include<iostream>
2 #include<cstdio>
3 #include<cstdlib>
4 #include<cstring>
5 #include<algorithm>
6 #include<vector>
7 using namespace std;
8
9 int n,q1,q2;
10 int f[10010],a[10010];
11 bool c[10010],flag[10010];
12 vector<int> tree[10010];
13
14 int find(int k)
15 {
16 if (f[k]==k) return k;
17 f[k]=find(f[k]);
18 return f[k];
19 }
20
21 int unions(int x,int y)
22 {
23 int xx=find(x),yy=find(y);
24 f[yy]=xx;
25 return 0;
26 }
27
28 int tarjan(int u)
29 {
30 //f[u]=u;
31 for (int i=0;i<tree[u].size();i++)
32 {
33 tarjan(tree[u][i]);
34 unions(u,tree[u][i]);
35 a[find(u)]=u;
36 }
37 c[u]=1;
38 if (q1==u && c[q2]) printf("%d\n",a[find(q2)]);
39 else if (q2==u && c[q1]) printf("%d\n",a[find(q1)]);
40 return 0;
41 }
42
43 int main()
44 {
45 int cases;
46 scanf("%d",&cases);
47 while (cases--)
48 {
49 scanf("%d",&n);
50 for (int i=1;i<=n;i++)
51 {
52 tree[i].clear();
53 f[i]=i;
54 a[i]=0;
55 c[i]=0;
56 flag[i]=1;
57 }
58 for (int i=1;i<n;i++)
59 {
60 int x,y;
61 scanf("%d%d",&x,&y);
62 flag[y]=0;
63 tree[x].push_back(y);
64 }
65 scanf("%d%d",&q1,&q2);
66 int i;
67 for (i=1;i<=n;i++)
68 if (flag[i]) break;
69 tarjan(i);
70 }
71 system("pause");
72 return 0;
73 }



posted on 2012-01-29 22:03  procedure2012  阅读(798)  评论(0编辑  收藏  举报