poj 1330 LCA最近公共祖先

今天学LCA,先照一个模板学习代码,给一个离线算法,主要方法是并查集加上递归思想。

 

再搞,第一个离线算法是比较常用了,基本离线都用这种方法了,复杂度O(n+q)。通过递归思想和并查集来寻找最近公共祖先,自己模拟下过程就可以理解了。

 

然后就是在线算法,在线算法方法就很多了,比较常用的是LCA的RMQ转换,然后还有线段树,DP等,最后效率最高的就是倍增法了每次查询O(LogN)

 

这道题是离线的。

给出离线的Tarjan和倍增算法吧。

 

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
#define MAXN 10001
int f[MAXN];
int r[MAXN];
int indegree[MAXN];
int vis[MAXN];
vector<int>hash[MAXN],Qes[MAXN];
int ancestor[MAXN];
void init(int n)
{
    int i;
    for(int i=1;i<=n;i++)
    {
        r[i]=1;
        f[i]=1;
        indegree[i]=0;
        vis[i]=0;
        ancestor[i]=0;
        hash[i].clear();
        Qes[i].clear();
    }
}
int find(int n)
{
    if(f[n]!=n)
        f[n]=find(f[n]);
    return f[n];
}

int Union(int x,int y)
{
    int a=find(x);
    int b=find(y);
    if(a==b)
        return 0;
    else if(r[a]<r[b])
    {
        f[a]=b;
        r[b]+=r[a];
    }
    else
    {
        f[b]=a;
        r[a]+=r[b];
    }
    return 1;
}
void LCA(int u)
{
    ancestor[u]=u;
    int size=hash[u].size();
    for(int i=0;i<size;i++)
    {
        LCA(hash[u][i]);
        Union(u,hash[u][i]);
        ancestor[find(u)]=u;
    }
    vis[u]=1;
    size=Qes[u].size();
    for(int i=0;i<size;i++)
    {
        if(vis[Qes[u][i]]==1)
        {
            printf("%d\n",ancestor[find(Qes[u][i])]);
            return ;
        }
    }
}

int main()
{
    int T,s,t,n;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        init(n);
        for(int i=1;i<=n-1;i++)
        {

            scanf("%d%d",&s,&t);
            hash[s].push_back(t);
            indegree[t]++;
        }
        scanf("%d%d",&s,&t);
        Qes[s].push_back(t);
        Qes[t].push_back(s);
        for(int j=1;j<=n;j++)
        {
            if(indegree[j]==0)
            {
                LCA(j);
                break;
            }
        }
    }
    return 0;
}


 倍增法:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
using namespace std;
const int N=10002;
const int Log=20;
int dp[N][Log],depth[N],deg[N];
struct Edge
{
    int to;
    Edge *next;
}edge[2*N],*cur,*head[N];
void addedge(int u,int v)
{
    cur->to=v;
    cur->next=head[u];
    head[u]=cur++;
}
void dfs(int u)
{
    depth[u]=depth[dp[u][0]]+1;
    for(int i=1;i<Log;i++) dp[u][i]=dp[dp[u][i-1]][i-1];
    for(Edge *it=head[u];it;it=it->next)
    {
        dfs(it->to);
    }
}
int lca(int u,int v)
{
    if(depth[u]<depth[v])swap(u,v);
    for(int st=1<<(Log-1),i=Log-1;i>=0;i--,st>>=1)
    {
        if(st<=depth[u]-depth[v])
        {
            u=dp[u][i];
        }
    }
    if(u==v) return u;
    for(int i=Log-1;i>=0;i--)
    {
        if(dp[v][i]!=dp[u][i])
        {
            v=dp[v][i];
            u=dp[u][i];
        }
    }
    return dp[u][0];
}
void init(int n)
{
    for(int i=0;i<=n;i++)
    {
        dp[i][0]=0;
        head[i]=NULL;
        deg[i]=0;
    }
    cur=edge;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n,u,v;
        scanf("%d",&n);
        init(n);
        for(int i=0;i<n-1;i++)
        {
            scanf("%d%d",&u,&v);
            addedge(u,v);
            deg[v]++;
            dp[v][0]=u;
        }
        for(int i=1;i<=n;i++)
        {
            if(deg[i]==0)
            {
                dfs(i);
                break;
            }
        }
        scanf("%d%d",&u,&v);
        printf("%d\n",lca(u,v));
    }
    return 0;
}


 

posted @ 2013-08-17 21:04  amourjun  阅读(101)  评论(0编辑  收藏  举报