tarjan&&LCA模板

//求强连通分量
int n,m;
int dfn[N],low[N],instk[N],sccno[N],index,scc_cnt;
stack<int> stk;
vector<int> e[N],scc[N];
void Init()
{
    for(int i=0;i<N;i++)
        dfn[i]=low[i]=sccno[i]=instk[i]=0;
    memset(e,0,sizeof(e));
    memset(scc,0,sizeof(scc));
    index=scc_cnt=0;
}
void Tarjan(int u)
{
    dfn[u]=low[u]=++index;
    stk.push(u);instk[u]=1;
    for(int i=0;i<e[u].size();i++)
    {
        int v=e[u][i];
        if(!dfn[v])
        {
            Tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(instk[v]) low[u]=min(low[u],dfn[v]);
    }
    if(dfn[u]==low[u])
    {
        scc_cnt++;
        while(1)
        {
            int now=stk.top();
            sccno[now]=scc_cnt;
            scc[scc_cnt].push_back(now);
            instk[now]=0;
            stk.pop();
            if(now==u) break;
        }
    }
}
//求无向图的割点和桥
struct edge
{
    int u,v;
    edge(int _u,int _v):u(_u),v(_v){}
};
int n,m;
int dfn[N],low[N],bccno[N],bcc_cnt,index;
int iscut[N];//割点的iscut为1
vector<edge> bridge;//桥保存在bridge中
stack<edge> stk;
vector<int> e[N],bcc[N];//bcc[i]表示编号i的分量的节点
void Init()
{
    for(int i=0;i<N;i++)
        dfn[i]=low[i]=bccno[i]=0;
    memset(e,0,sizeof(e));
    memset(bcc,0,sizeof(bcc));
    bcc_cnt=index=0;
}
void Tarjan(int u,int fa)
{
    int child=0;
    dfn[u]=low[u]=++index;
    for(int i=0;i<e[u].size();i++)
    {
        int v=e[u][i];
        edge t=edge(u,v);
        if(!dfn[v])
        {
            child++;
            stk.push(t);
            Tarjan(v,u);
            low[u]=min(low[u],low[v]);
            if(dfn[u]<=low[v])
            {
                iscut[u]=1;//割点
                if(dfn[u]<low[v]) bridge.push_back(t);//桥
                bcc[++bcc_cnt].clear();
                while(1)
                {
                    edge now=stk.top();
                    stk.pop();
                    if(bccno[now.u]!=bcc_cnt)
                    {
                        bcc[bcc_cnt].push_back(now.u);
                        bccno[now.u]=bcc_cnt;
                    }
                    if(bccno[now.v]!=bcc_cnt)
                    {
                        bcc[bcc_cnt].push_back(now.v);
                        bccno[now.v]=bcc_cnt;
                    }
                    if(now.u==u&&now.v==v) break;
                }
            }
        }
        else if(dfn[u]>dfn[v]&&v!=fa)
        {
            stk.push(t);
            low[u]=min(dfn[v],low[u]);
        }
    }
    if(fa==-1&&child==1) iscut[u]=0;
}
//倍增法求LCA
int n,x,y;
int dep[N],vis[N],dp[N][20],root;
vector<int> e[N];
void Init()
{
    for(int i=0;i<N;i++)
    {
        dep[i]=0;
        vis[i]=0;
        e[i].clear();
    }
    memset(dp,0,sizeof(dp));
}
void Dfs(int u)
{
    vis[u]=1;
    for(int i=0;i<(int)e[u].size();i++)
    {
        int v=e[u][i];
        if(!vis[v])
        {
            dep[v]=dep[u]+1;
            Dfs(v);
        }
    }
}
void St()
{
    for(int j=1;j<20;j++)
        for(int i=1;i<=n;i++)
            dp[i][j]=dp[dp[i][j-1]][j-1];
}
int Lca(int u,int v)
{
    if(dep[u]<dep[v]) swap(u,v);
    int tmp=dep[u]-dep[v];
    for(int i=19;i>=0;i--)
        if((1<<i)&tmp) u=dp[u][i];
    if(u==v) return u;
    for(int i=19;i>=0;i--)
    {
        if(dp[u][i]!=dp[v][i])
        {
            u=dp[u][i];
            v=dp[v][i];
        }
    }
    return dp[u][0];
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        Init();
        scanf("%d",&n);
        for(int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            e[u].push_back(v);
            dp[v][0]=u;
            if(!dp[u][0]) root=u;
        }
        dep[root]=1;
        Dfs(root);
        St();
        scanf("%d%d",&x,&y);
        printf("%d\n",Lca(x,y));
    }
}
//tarjan求LCA
int n,u,v;
int par[N],root[N],vis[N];
vector<int> e[N];
void Init()
{
    for(int i=0;i<N;i++)
    {
        par[i]=i;
        root[i]=1;
        vis[i]=0;
        e[i].clear();
    }
}
int Find(int x)
{
    if(x!=par[x]) return par[x]=Find(par[x]);
    else return par[x];
}
void Union(int x,int y)
{
    int tx=par[x],ty=par[y];
    if(tx==ty) return;
    par[ty]=tx;
}
void Lca(int x)
{
    for(int i=0;i<(int)e[x].size();i++)
    {
        int y=e[x][i];
        Lca(y);
        Union(x,y);
    }
    vis[x]=1;
    if(x==u&&vis[v])
    {
        printf("%d\n",Find(v));
        return;
    }
    if(x==v&&vis[u])
    {
        printf("%d\n",Find(u));
        return;
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        Init();
        scanf("%d",&n);
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&u,&v);
            e[u].push_back(v);
            root[v]=0;
        }
        scanf("%d%d",&u,&v);
        for(int i=1;i<=n;i++) if(root[i]) {Lca(i);break;}
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值