LCA问题

最近公共祖先问题 : http://poj.org/problem?id=1330

#include <iostream>
#include <memory.h>
#include <vector>
#include <algorithm>
using namespace std;

/**
理解:
对于节点 a ,左孩子 b ,右孩子 c
1、a与b合并的时候 是当 b 全部遍历完时,遍历不完 不会合并
    则此时 b的最近祖先是 b
    祖先是运行过程中动态更新的
2、所谓的离线 就是先将所有的query读入,然后处理
*/

//此处并查集采用链式树形存储
const int N = 10010;
int father[N];
int ancestor[N];
int rank[N];
int indegree[N];

std::vector<int > adj[N];   //树的临间表存储
std::vector<int > tmp[N];   //查询邻间表存储

bool visited[N] ;       //一个很重要的标志量

void adjinit()
{
    int i=0;
    for(i=0;i<N;i++)
    {
        father[i] = i;      //设置自己的为自己的父亲
        adj[i].clear();
        tmp[i].clear();
    }
    memset(visited,false,sizeof(visited));
    fill(rank,rank+N,1);    //初始化 每个集合的树的高度
    memset(indegree,0,sizeof(indegree));    //初始化每个顶点的入度,
}

//查询 带有路径压缩的查询  查询集合的标志
int findset(int u)
{
    if(father[u] == u)
        return u;
    //带 路径压缩的 查询
    father[u] = findset(father[u]);
    return father[u];
}
void unionset(int u,int v)
{
    u = findset(u);
    v = findset(v);
    if( u == v) //属于一个集合
        return  ;
    //不属于一个集合,要进行集合的合并
    //使用按秩合并方式
    if(rank[u] > rank[v])
    {
        father[v] = u;
    }
    else
    {
        father[u] = v;
        if(rank[u] == rank[v])
            rank[v] += 1;   //高度 +1
    }
}

void LCA(int u) //u为树根
{
    //father[u] = u;  //首先make_set
    ancestor[ findset(u) ] = u;   //设置u所在的集合的祖先为 u
    //遍历子树
    vector<int>::size_type i;
    for(i=0;i<adj[u].size();i++)
    {
        LCA(adj[u][i]); //深度优先遍历子树
        unionset(u,adj[u][i]);  //该子树遍历完之后与 祖先u合并
        ancestor[findset(u)] = u;//设置u所在的集合的祖先为 u
    }
    visited[u] = true;
    for(i=0;i<tmp[u].size();i++)    //遍历查询 查找包含当前节点 的query
    {
        if( visited[tmp[u][i]] )    //如果query的另一个节点 v 已经标记过 则查找他的祖先 即为最小公共祖先
            cout<<ancestor[findset(tmp[u][i])]<<endl;
    }
}
int main()
{
    int k,n,u,v;
    cin>>k; //输入test case
    while(k--)
    {
        cin>>n; //节点的个数
        int i=0;
        adjinit();  //初始化

        //接下来输入 n-1条边 与 1 个query
        for(i=0; i<n-1 ; i++)
        {
            cin>>u>>v;
            adj[u].push_back(v);    //邻间表存储
            indegree[v]++;  //入度++
        }
        //输入query
        cin>>u>>v;
        tmp[u].push_back(v);    //两次输入 是为了便于查询
        tmp[v].push_back(u);
        for(i=1;i<=n;i++)
            if(indegree[i] == 0)    //找到树根 并且开始 查找
                LCA(i);
    }
    return 0;
}

借鉴博客: http://blog.csdn.net/xuzengqiang/article/details/7334330

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值