Tarjan求LCA

https://www.luogu.com.cn/problem/P3379

\(Tarjan\)\(LCA\)

\(Tarjan\)\(LCA\)是一种离线求\(LCA\)的做法

\(dfs\)访问每个节点,当一个节点被访问结束后,直接将该节点并在它的父亲上,然后处理询问

\(vector\)储存一端在\(u\)的询问,倘若另一端\(v\)已经被访问到了,那么把\(v\)所并的集合的祖先取出就是该询问的答案。因为一个集合为一个子树,\(v\)已经被访问到了,那么这个集合就是包含\(u,v\)的最小子树根节点,当然是\(LCA\)

不要把并查集中的\(=\)写成\(==\)

\(Code:\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#define N 500005
using namespace std;
int n,m,rt,x,y,tot,f[N],fr[N],nxt[N << 1],d[N << 1];
int rf[N],ans[N];
struct node
{
    int x,y;
    node (int xx=0,int yy=0)
    {
        x=xx,y=yy;
    }
};
vector<node>e[N];
void add(int x,int y)
{
    tot++;
    d[tot]=y;
    nxt[tot]=fr[x];
    fr[x]=tot;
}
int getf(int x)
{
    return (x==rf[x])?x:(rf[x]=getf(rf[x]));
}
void dfs(int u)
{
    rf[u]=u;
    for (int i=fr[u];i;i=nxt[i])
    {
        int v=d[i];
        if (v==f[u])
            continue;
        f[v]=u;
        dfs(v);
        rf[v]=u;
    }
    for (vector<node> :: iterator it=e[u].begin();it!=e[u].end();++it)
        if (rf[it->x])
            ans[it->y]=getf(it->x);
}
int main()
{
    scanf("%d%d%d",&n,&m,&rt);
    for (int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y),add(y,x);
    }
    for (int i=1;i<=m;i++)
        scanf("%d%d",&x,&y),e[x].push_back(node(y,i)),e[y].push_back(node(x,i));
    dfs(rt);
    for (int i=1;i<=m;i++)
        printf("%d\n",ans[i]);
    return 0;
}

可以使用按秩合并优化,但是必须注意,因为采用了按秩合并,那么集合的祖先就不再是真正的根节点了,记\(rg_i\)为以\(i\)为祖先的集合的真正根节点,这很容易维护,因为我们每次都把儿子节点\(v\)的集合并到父亲\(u\)上,因此合并完后集合的\(rg\)值为\(u\)

\(Code:\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#define N 500005
using namespace std;
int n,m,rt,x,y,tot,f[N],fr[N],nxt[N << 1],d[N << 1];
int rf[N],rg[N],rz[N],ans[N];
struct node
{
    int x,y;
    node (int xx=0,int yy=0)
    {
        x=xx,y=yy;
    }
};
vector<node>e[N];
void add(int x,int y)
{
    tot++;
    d[tot]=y;
    nxt[tot]=fr[x];
    fr[x]=tot;
}
int getf(int x)
{
    return (x==rf[x])?x:(rf[x]=getf(rf[x]));
}
void dfs(int u)
{
    rf[u]=u;
    rg[u]=u;
    rz[u]=1;
    for (int i=fr[u];i;i=nxt[i])
    {
        int v=d[i];
        if (v==f[u])
            continue;
        f[v]=u;
        dfs(v);
        int fu=getf(u);
        int fv=getf(v);
        if (rz[fv]<=rz[fu])
        {
            rz[fu]+=rz[fv];
            rf[fv]=fu;
        } else
        {
            rf[fu]=fv;
            rz[fv]+=rz[fu];
            rg[fv]=u;
        }
    }
    for (vector<node> :: iterator it=e[u].begin();it!=e[u].end();++it)
        if (rf[it->x])
            ans[it->y]=rg[getf(it->x)];
}
int main()
{
    scanf("%d%d%d",&n,&m,&rt);
    for (int i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y),add(y,x);
    }
    for (int i=1;i<=m;i++)
        scanf("%d%d",&x,&y),e[x].push_back(node(y,i)),e[y].push_back(node(x,i));
    dfs(rt);
    for (int i=1;i<=m;i++)
        printf("%d\n",ans[i]);
    return 0;
}
posted @ 2020-09-11 14:52  GK0328  阅读(86)  评论(0编辑  收藏  举报