版权声明:本文为博主原创文章,转载请附上注明就行_(:з」∠)_。 https://blog.csdn.net/vocaloid01/article/details/82081526
Tarjan 算法求 LCA 的时间复杂度为 O(n+q) ,是一种离线算法,要用到并查集。
ps:时间复杂度其实还需要考虑并查集操作的时间复杂度 ,但是由于在多数情况下,路径压缩并查集的单次操作复杂度可以看做 O(1),所以直接近似为 O(n+q) 。
const int MAXN = ;//最大点数
pair<int,int> P[205];//存询问边
int lca[205];//存询问边对应的最近公共祖先
//------------------------------------------------------------
struct Edge{//存树边
int to,next,w;//w为边权
}E[MAXN*2];
int head[MAXN],tot;
inline void Add(int from,int to,int w){
E[++tot].next = head[from];
E[tot].to = to;
E[tot].w = w;
head[from] = tot;
E[++tot].next = head[to];
E[tot].to = from;
E[tot].w = w;
head[to] = tot;
}
//------------------------------------------------------------
struct Query{//存每个点对应的询问边
int to,next,id;
}Q[405];
int headQ[MAXN],totq;
inline void AddQ(int from,int to,int id){
Q[++totq].next = headQ[from];
Q[totq].to = to;
Q[totq].id = id;
headQ[from] = totq;
Q[++totq].next = headQ[to];
Q[totq].to = from;
Q[totq].id = id;
headQ[to] = totq;
}
//------------------------------------------------------------
bool vis[MAXN];
int fa[MAXN];//并查集祖先数组
int Find(int x){
if(fa[x] == x)return x;
return fa[x] = Find(fa[x]);
}
void Union(int a,int b){
int A = Find(a);
int B = Find(b);
if(A != B)fa[B] = A;
}
void Tarjan(int rt){
vis[rt] = true;
int to;
for(int i=head[rt] ; i ; i=E[i].next){
to = E[i].to;
if(!vis[to]){
Tarjan(to);
Union(rt,to);
}
}
for(int i=headQ[rt] ; i ; i=Q[i].next){
to = Q[i].to;
if(vis[to]){
lca[Q[i].id] = Find(to);
}
}
}
//------------------------------------------------------------
inline void init(int n){
for(int i=0 ; i<=n ; ++i)fa[i] = i;
memset(vis,false,sizeof vis);
memset(head,0,sizeof head);
memset(headQ,0,sizeof headQ);
tot = totq = 0;
}