tarjan求LCA的体会

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int N=500005;
int n,m,s,cnt,num;//树的结点个数、询问的个数和树根结点的序号。
struct EDGE{
    int v,next;
};
struct QUE{
    int node,next,id;
};
QUE que[N*3];
EDGE e[N*3];
int vis[N],head[N],vhead[N],fa[N],ans[N];
void add_e(int from,int to)
{
    e[++cnt].v=to;
    e[cnt].next=head[from];
    head[from]=cnt;
}
int find(int x) {
    if(x==fa[x]) return x;
    fa[x]=find(fa[x]);
    return fa[x];
}
void add_q(int u,int to,int id_)
{
    que[++num].id=id_;
    que[num].node=to;
    que[num].next=vhead[u];
    vhead[u]=num;
}
void tarjan(int s,int from)
{
    for(int i=head[s];i;i=e[i].next)
    {
        int v=e[i].v;
        if(from!=v)
        tarjan(v,s),fa[v]=s;
    }
    for(int i=vhead[s];i;i=que[i].next)
    {
        int v=que[i].node;
        if(!vis[v]) continue;
        ans[que[i].id]=find(v);
    }
    vis[s]=1;
}
int main()
{
    /*freopen("in.in","r",stdin);
    freopen("out.txt","w",stdout);*/
    scanf("%d%d%d",&n,&m,&s);
    for(int i=1;i<n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        add_e(u,v),add_e(v,u);//不知道u和v深度的大小关系,所以要加两条边 
    }
    for(int i=1;i<=n;i++) fa[i]=i; 
    for(int i=1;i<=m;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        add_q(u,v,i),add_q(v,u,i);
    }
    tarjan(s,0);
    
    for(int i=1;i<=m;i++)
    cout<<ans[i]<<endl;
    return 0;
}

①给que也要开结构体,避免o(m)查询;

②不用一个个倒着找最深的祖先,用并查集加路径压缩。

③跑深搜的时候,要记得加上to[i]!=s,因为加入的边都是无向边,不加的话可能会死循环。

原文地址:https://www.cnblogs.com/Neptune0/p/11832223.html