POJ 1330 Nearest Common Ancestors

题目:

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

题意:

给出一棵树,求其中两个点的最近公共祖先。

思路:

测试模版。

代码:

const int MAXN = 101001;
const int MAXM = 101001;
const int MAXQ = 101001;
struct Tree{
    int head[MAXN];//前向星存图
    int next[MAXM];
    int to[MAXM];
    int val[MAXM];//权值
    int pos;
    Tree()
    {
        clear();
    }
    void clear()
    {
        memset(head,-1,sizeof(head));
        memset(val,0,sizeof(val));
        pos = 0;
    }
    void add(int u,int v,int w)
    {
        val[pos] = w;
        to[pos] = v;
        next[pos] = head[u];
        head[u] = pos++;
    }
}tree;

bool v[MAXN];
int in[MAXN];//入度
int dist[MAXN];//与根节点距离
int father[MAXN];//并查集处理
int n,m,q;
vector<int>query[MAXQ],num[MAXQ];
int ans[MAXQ];

void Init()
{
    memset(v,0,sizeof(v));
    memset(in,0,sizeof(in));
    memset(ans,0,sizeof(ans));
    for(int i=0;i<MAXQ;i++)
    {
        query[i].clear();
        num[i].clear();
    }
    tree.clear();
}
int Find(int x)
{
    if(father[x] != x)
        father[x] = Find(father[x]);
    return father[x];
}
void getDist(int u)//计算节点到根距离
{
    for(int i = tree.head[u];i!=-1;i=tree.next[i])
    {
        dist[tree.to[i]] = dist[u] + tree.val[i];
        getDist(tree.to[i]);
    }
}
void Tarjan(int u)
{
    father[u] = u;//当访问到一个节点的时候,先将其自己形成一个集合
    v[u] = true;//标记访问
    for(int i = tree.head[u];i!=-1;i=tree.next[i])
    {
        Tarjan(tree.to[i]);//递归处理
        father[tree.to[i]] = u;//处理结束后,将子节点集合加到父节点
    }
    for(int i = 0; i < query[u].size(); i++)//便利询问
    {
        if(v[query[u][i]])
        {
            ans[num[u][i]] =Find(query[u][i]);
        }
    }
}
int main()
{
    int x,y,t,T;
    #ifndef ONLINE_JUDGE
        freopen("test.txt","r",stdin);
    #endif
    scanf("%d",&T);
    while(T--)
    {
        Init();
        scanf("%d",&n);
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            tree.add(x,y,1);
            in[y]++;
        }
        scanf("%d%d",&x,&y);
        query[x].push_back(y);
        query[y].push_back(x);
        num[x].push_back(1);
        num[y].push_back(1);
        for(int i=1;i<=n;i++)
            if(in[i] == 0)
            {
                dist[i]=0;
                getDist(i);
                Tarjan(i);
                break;
            }
        printf("%d\n",ans[1]);
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值