//求强连通分量
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;}
}
}
tarjan&&LCA模板
最新推荐文章于 2022-01-27 15:08:22 发布