我们便以tarjan_LCA为模板,顺便复习复习tarjan_LCA。
node
#include<cstdio>
#define N 500010
using namespace std;
struct node{int v,fr;}e[N<<1];
struct edge{int v,fr,num;}g[N<<1];
int tail[N],head[N],lca[N],fa[N];
int n,m,s,cnt=0,cnt1=0;
bool bz[N];
inline int read()
{
int x=0; char c=getchar();
while (c<'0' || c>'9') c=getchar();
while (c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x;
}
inline void add(int u,int v) {e[++cnt]=(node){v,tail[u]}; tail[u]=cnt;}
inline void add1(int u,int v,int num) {g[++cnt1]=(edge){v,head[u],num},head[u]=cnt1;}
int find(int x) {return !fa[x] ? x:fa[x]=find(fa[x]);}
void dfs(int x)
{
for (int p=head[x],v;p;p=g[p].fr)
{
v=g[p].v;
if (!bz[v]) continue;
lca[g[p].num]=find(v);
}
for (int p=tail[x],v;p;p=e[p].fr)
{
v=e[p].v;
if (bz[v]) continue;
bz[v]=1,dfs(v),fa[v]=x;
}
}
int main()
{
freopen("tarjan.in","r",stdin);
freopen("tarjan.out","w",stdout);
n=read(),m=read(),s=read();
for (int i=1,u,v;i<n;i++)
u=read(),v=read(),add(u,v),add(v,u);
for (int i=1,u,v;i<=m;i++)
u=read(),v=read(),add1(u,v,i),add1(v,u,i);
bz[s]=1,dfs(s);
for (int i=1;i<=m;i++) printf("%d
",lca[i]);
return 0;
}
这便是模板了(来源于jz_junior_oj_2263. 最近公共祖先(LCA))
然后我们来看一看如何打人工栈。
人工栈,顾名思义,就是人为的去模拟栈这个东东。
我们要如何来模拟dfs呢?我们就按照dfs的性质来想想。
它是不停地往下递归,所以我们也要如此
我们用前向星来存储询问和边。
每次走完一条边,我们就将tail数组更新一番。
下面大概模拟一下这个过程:
//dfs版
void dfs(int x)
{
'A';
for (int p=tail[x];p;p=e[p].fr)
if ('B')
{
// 此处相当于'A'
dfs(e[p].v);
'C';
}
// 此处相当于'C'
}
//人工栈版
while (top)
{
x=z[top];to=e[tail[x]].v;
while (!'B')
tail[x]=e[tail[x]].fr,to=e[tail[x]].v;
if (!tail[x])
{
'C';
top--;
continue;
}
'A';
z[++top]=to;
}
大概就是这样子的了,下面来看一看模板(开始的LCA)改成人工栈后的样子吧!
node
#include<cstdio>
#define N 500010
using namespace std;
struct node{int v,fr;}e[N<<1];
struct edge{int v,fr,num;}g[N<<1];
int tail[N],head[N],lca[N],fa[N],fat[N],z[N];
int n,m,s,cnt=0,cnt1=0,top,x,to;
bool bz[N];
inline int read()
{
int x=0; char c=getchar();
while (c<'0' || c>'9') c=getchar();
while (c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x;
}
inline void add(int u,int v) {e[++cnt]=(node){v,tail[u]}; tail[u]=cnt;}
inline void add1(int u,int v,int num) {g[++cnt1]=(edge){v,head[u],num},head[u]=cnt1;}
int gf(int x) {return !fa[x] ? x:fa[x]=gf(fa[x]);}
int main()
{
freopen("tarjan.in","r",stdin);
freopen("tarjan.out","w",stdout);
n=read(),m=read(),s=read();
for (int i=1,u,v;i<n;i++)
u=read(),v=read(),add(u,v),add(v,u);
for (int i=1,u,v;i<=m;i++)
{
u=read(),v=read();
if (u==v) {lca[i]=u; continue;}
add1(u,v,i),add1(v,u,i);
}
bz[s]=1;z[1]=s,top=1;
while (top)
{
x=z[top];
to=e[tail[x]].v;
while (tail[x] && bz[to])
tail[x]=e[tail[x]].fr,to=e[tail[x]].v;
if (!tail[x]) {fa[x]=fat[x],top--; continue;}
bz[to]=1,z[++top]=to,fat[to]=x;
for (int p=head[to],v;p;p=g[p].fr)
{
v=g[p].v;
if (!bz[v]) continue;
lca[g[p].num]=gf(v);
}
}
for (int i=1;i<=m;i++) printf("%d
",lca[i]);
return 0;
}