如果我來到了我們的 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() 還不帶路徑壓縮,但一定要路徑壓縮