Poj 1470 Closest Common Ancestors(Tarjin 求LCA)

本文通过解决一棵树上两节点最近公共祖先的问题,详细记录了使用Tarjan算法的过程及调试经历。从邻接表的构建到Tarjan算法的具体实现,再到调试过程中遇到的各种问题及其解决方法都有详尽描述。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给出一棵树上根节点与子节点的关系,求两节点的最近公共祖先

这题虽然是比较裸的Tarjin,但是我WA到死!。。刚开始我用邻接表存储边的关系和询问关系,一直WA,我以为用邻接表的过程中出了错误,所以注释掉,改用vector来存储,后面OLE!唉~AC之路真艰难,,,后面一个一个的检查,实在找不出,叫龙帮我看了下,后面我发现了一个初始化问题,然后改了一交A!。。马上我就跑到原来用邻接表写的那个代码,改了改,一交RE!泪喷~把数组开大A!我可真是幸福呀。。。

代码:

#include <iostream>
#include <stdio.h>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <map>
#include <queue>
#define lson l,mid,num<<1
#define rson mid+1,r,num<<1|1
using namespace std;
const int M=905;
int in[M],ans[M],fa[M],ance[M],head[M],head2[M];
int e,e2,vis[M];
struct node
{
    int v,next;
} edge[2*M];
struct node1
{
    int v,next;
} edge2[M*M];//这个好坑爹
void add(int u,int v)
{
    edge[e].v=v;
    edge[e].next=head[u];
    head[u]=e++;
}
void add2(int u,int v)
{
    edge2[e2].v=v;
    edge2[e2].next=head2[u];
    head2[u]=e2++;
    edge2[e2].v=u;
    edge2[e2].next=head2[v];
    head2[v]=e2++;
}
int find(int x)
{
    return x==fa[x]?x:fa[x]=find(fa[x]);
}
void Union(int u,int v)
{
    fa[find(v)]=u;
}
void tarjin(int u)
{

    ance[u]=u;
    for(int i=head[u]; i!=-1; i=edge[i].next)
    {
        if(!vis[edge[i].v])
        {
            tarjin(edge[i].v);
            Union(u,edge[i].v);
            ance[find(u)]=u;
        }
    }
    vis[u]=1;
    for(int i=head2[u]; i!=-1; i=edge2[i].next)
    {
        int v=edge2[i].v;
        if(vis[v])
        {
            ans[find(v)]++;
        }
    }
}
int main()
{
    int n,v,m,q,u;
    while(scanf("%d",&n)!=EOF)
    {
        memset(head,-1,sizeof(head));
        memset(head2,-1,sizeof(head2));
        for(int i=1; i<=n; i++)
        {
            ance[i]=0;
            in[i]=0;
            ans[i]=vis[i]=0;//vis[i]=0!!!!
            fa[i]=i;
        }
        e=e2=0;
        for(int i=1; i<=n; i++)
        {
            scanf("%d:(%d)",&u,&m);
            for(int i=0; i<m; i++)
            {
                scanf("%d",&v);
                add(u,v);
                in[v]=1;
            }
        }
        int x,y;
        scanf("%d",&q);
        while(q--)
        {
            while(getchar()!='(');
            scanf("%d %d",&x,&y);
            while(getchar()!=')');
            add2(x,y);
        }
        for(int i=1; i<=n; i++)
        {
            if(in[i]==0)
            {
                tarjin(i);
                break;
            }
        }
        for(int i=1; i<=n; i++)
        {
            if(ans[i]>0)
            {
                printf("%d:%d\n",i,ans[i]);
            }
        }
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值