http://poj.org/problem?id=1330

这个是tarjian离线的版本:

对于一个父亲的所有孩子。我们都去递归Lca。如果当前点是要询问的那个两个点中的一个而且另外一个已经访问过了。就输出。

方法一:Tarjan离线算法
在学习离线算法的时候先需要先巩固一下深度搜索,并查集
Tarjan离线算法是基于深度优先搜索的,我们从根开始向下搜索,搜到一个节点的时候首先判断该节点所有子节点是否访问过,如果都已经访问过,则判断该节点是否询问点里面的其中一个,如果是,则判断跟它相对应的那个点是否已经访问过,如果访问过,则他们的最近公共祖先便是已经访问过的那个节点的当前节点,如果另外一个节点没有访问,则继续进行深度搜索。

 

 1 #include<iostream>
 2 #include<string.h>
 3 #include<algorithm>
 4 #include<stdio.h>
 5 #define maxn 12000
 6 #include<vector>
 7 using namespace std;
 8 int father[maxn];
 9 int  visit[maxn];
10 int  root[maxn];
11 vector<int>node[maxn];
12 int st,en;
13 int n;
14 void init()
15 {
16     cin>>n;
17     for(int i=1;i<=n;i++)
18     {
19         father[i]=i;
20         root[i]=1;
21         visit[i]=0;
22         node[i].clear();
23     }
24     for(int i=1;i<n;i++)
25     {
26         int a,b;
27         cin>>a>>b;
28         node[a].push_back(b);
29         root[b]=0;
30     }
31     cin>>st>>en;
32 }
33 
34 int find(int a)
35 {
36        if(father[a]!=a)
37        {
38            father[a]=find(father[a]);
39        }
40        return father[a];
41 }
42 void Union(int a,int b)
43 {
44     int fa=find(a);
45     int fb=find(b);
46     if(fa!=fb)
47     father[fb]=fa;
48 }
49 
50 void Lca(int parent)
51 {
52     for(int i=0;i<node[parent].size();i++)
53     {
54         Lca(node[parent][i]);
55         Union(parent,node[parent][i]);
56     }
57     visit[parent]=1;
58     if(parent==st&&visit[en])
59     {
60         cout<<find(en)<<endl;
61         return ;
62     }
63     else
64     if(parent==en&&visit[st])
65     {
66         cout<<find(st)<<endl;
67         return ;
68     }
69 }
70 
71 int main()
72 {
73     int test;
74     cin>>test;
75     for(int i=1;i<=test;i++)
76     {
77         init();
78 
79         for(int i=1;i<=n;i++)
80             if(root[i])
81             {
82 
83                 Lca(i);
84                 break;
85             }
86     }
87     //system("pause");
88     return 0;
89 }

 

 这个是在线的版本

#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<math.h>
#define maxn 10005
using namespace std;
vector<int>node[maxn];
int indegree[maxn];
int E[maxn*2+2];
int R[maxn];
int D[maxn*2+2];
int dp[maxn*2+2][100];
int n;
int st;
int en;
int p;
void init()
{
    cin>>n;
        for(int i=1;i<=n;i++)
    {
        node[i].clear();
        indegree[i]=0;
        }
    for(int i=1;i<n;i++)
    {
    int a,b;
    cin>>a>>b;
    node[a].push_back(b);
    indegree[b]++;
    }
    p=0;
    cin>>st>>en;
}

void dfs(int root,int deep)
{
    p++;
    E[p]=root;
    D[p]=deep;
    R[root]=p;
    for(int i=0;i<node[root].size();i++)
    {
        dfs(node[root][i],deep+1);
        p++;
        E[p]=root;
        D[p]=deep;
    }
}
int min(int a,int b)
{
    return D[a]<D[b]?a:b;
}

void  Rmq(int a[],int num)
{
    memset(dp,0,sizeof(dp));
    for(int i=1;i<num;i++)
        dp[i][0]=i;
    int k=log((double)(num-1))/log(2.0);
    for(int j=1;j<=k;j++)
        for(int i=1;i+(1<<j)-1<num;i++)
        {
  dp[i][j]=D[dp[i][j-1]]<D[dp[i+(1<<(j-1))][j-1]]?dp[i][j-1]:dp[i+(1<<(j-1))][j-1];
        }
}

int Lca(int a[],int st,int en)
{
   int k=log(double(en-st+1))/log(2.0);
   return D[dp[st][k]]<D[dp[en-(1<<k)+1][k]]?dp[st][k]:dp[en-(1<<k)+1][k];
}
int main()
{
    int test;
    cin>>test;
    for(int i=1;i<=test;i++)
    {
        init();
        int root;
        for(int i=1;i<=n;i++)
                   if(!indegree[i])
        {root=i;break;}
        dfs(root,0);
        Rmq(D,2*n);

        if(R[st]<R[en])
            cout<<E[Lca(D,R[st],R[en])]<<endl;
        else
            cout<<E[Lca(D,R[en],R[st])]<<endl;
    }
    system("pause");
    return 0;
}

 

posted on 2012-08-22 15:54  一把刷子  阅读(209)  评论(0编辑  收藏  举报