如果我来到了我们的 LCA,我是不是就可以假装偶遇你了
首先是倍增法,和 ST 表如出一辙呢。
注意 N 通常在 5e5 的范围
点击查看代码
int head[N], cnt;
struct Edge{
int from, to, nxt;
}e[N << 1];
void add(int u, int v){
e[++cnt].from = u;
e[cnt].to = v;
e[cnt].nxt = head[u];
head[u] = cnt;
}
int fa[N][20], deep[N];
void dfs(int x, int father){
deep[x] = deep[father] + 1;
fa[x][0] = father;
for(int i = 1; (1 << i) <= deep[x]; i++){
fa[x][i] = fa[fa[x][i - 1]][i - 1];
}
for(int i = head[x]; i != 0; i = e[i].nxt){
int v = e[i].to;
if(v != father)
dfs(v, x);
}
}
int LCA(int x, int y){
if(deep[x] < deep[y]) swap(x, y);
for(int i = 19; i >= 0; i--)
if(deep[x] - (1 << i) >= deep[y])
x = fa[x][i];
if(x == y) return x;
// x 和 y 一起向上跳
for(int i = 19; i >= 0; i--){
if(fa[x][i] != fa[y][i]){
x = fa[x][i];
y = fa[y][i];
}
}
return fa[x][0];
}
然后是 Tarjan 的算法,这里的代码将询问用链式前向星方式存储
点击查看代码
int fa[N], ans[N];
bool vis[N];
int head[N], cnt;
struct Edge{
int from, to, nxt;
}e[N << 1];
void add(int u, int v){
e[++cnt].from = u;
e[cnt].to = v;
e[cnt].nxt = head[u];
head[u] = cnt;
}
int head_query[N], cnt_query;
struct Query{
int from, to, num, nxt;
}q[N << 1];
void add_query(int u, int v, int num){
q[++cnt_query].from = u;
q[cnt_query].to = v;
q[cnt_query].nxt = head_query[u];
q[cnt_query].num = num;
head_query[u] = cnt_query;
}
int find_set(int x){
if(x != fa[x]) fa[x] = find_set(fa[x]);
return fa[x];
}
void Tarjan(int x){
vis[x] = true;
for(int i = head[x]; i != 0; i = e[i].nxt){
int v = e[i].to;
if(!vis[v]){
Tarjan(v);
fa[v] = x;
}
}
for(int i = head_query[x]; i != 0; i = q[i].nxt){
int v = q[i].to;
if(vis[v]){
ans[q[i].num] = find_set(v);
}
}
}
书上代码 find_set() 还不带路径压缩,但一定要路径压缩
标签:Tarjan,int,代码,fa,LCA,倍增 From: https://www.cnblogs.com/9102qyy/p/18218935