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;
}