题解 P3379 【【模板】最近公共祖先(LCA)】
Tarjan的lca题解
blog
Tarjan采用离线的方式回答问题,用深搜和并查集实现
因为树其实可以看成是图,所以就用链式前向星来存储
对它的子树遍历,如果已经访问过则得到最近公共祖先
如果未访问过则不变
最后在并查集里合并子树
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cctype>
long long read(){
long long num=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch)){
num=num\*10+ch-'0';
ch=getchar();
}
return num\*f;
}
using namespace std;
int father[500010];
int head [500010];
int qhead [500010];
int que [500010];
struct Edge{
int next,to;
}edge[1000010];
struct qEdge{
int next,to,ans;
qEdge(){ans=0;}
}q[1000010];
int cnt;
void add(int x,int y){
cnt++;
edge[cnt].to=y;
edge[cnt].next=head[x];
head[x]=cnt;
}
void qadd(int x,int y,int k){
q[k].to=y;
q[k].next=qhead[x];
qhead[x]=k;
}
int find(int x){
if(father[x]!=x) father[x]=find(father[x]);
return father[x];
}
void unionn(int x,int y){
x=find(x);y=find(y);
father[y]=x;
}
void tarjan(int x){
que[x]=1;
for(int i=head[x];i;i=edge[i].next){
int to=edge[i].to;
if(!que[to]){
tarjan(to);
unionn(x,to);
}
}
for(int i=qhead[x];i;i=q[i].next){
int to=q[i].to;
if(que[to]==2){
q[i].ans=find(to);
if(i%2) q[i+1].ans=q[i].ans;
else q[i-1].ans=q[i].ans;
}
}
que[x]=2;
}
int main(){
int n=read(),m=read(),s=read();
for(int i=1;i<n;++i){
int x=read(),y=read();
add(x,y);
add(y,x);
father[i]=i;
}
father[n]=n;
for(int i=1;i<=m;++i){
int x=read(),y=read();
qadd(x,y,i\*2-1);
qadd(y,x,i\*2);
}
tarjan(s);
for(int i=1;i<=n;++i){
printf("%d\n",q[i\*2].ans);
}
return 0;
}