一道板題
維護陣列 \(f[ i ][ j ]\) 表示\(i\) 號節點的第\(2^j\) 級祖先,沒有則為\(0\)
轉移方程:
\[f[i][j] =f[f[i][j-1]][j-1] (j>0)
\]\[f[i][j]=fa[i] (j=0)
\]將k從大到小迴圈,如果\(x\),\(y\) 的\(2^k\) 級祖先相同則不做改變,不同則將 \(x\) ,\(y\) 更新為各自的\(2^k\) 級祖先。
當 \(k=0\) 時,lca為此時 \(x\) ,\(y\) 的父親
令 \(dep[a]>dep[b]\) ,將 \(a\) 向上跳,直到 \(a\) 的深度與 \(b\) 的深度相同為止,於是變轉換為相同深度求 lca
時間複雜度:
預處理: \(o(nlogn)\) ,單詞詢問: \(o(logn)\)
空間複雜度: \(nlogn\)
**示例:
預處理:
void bfs(int root)
} }}
主體:
int lca(int a,int b)
利用遞迴的回溯做標記,遍歷一次後標記為\(1\) ,回溯後標記為\(2\)
把詢問轉換成離線做法,先把所有的詢問存下來,最後統一輸出
優化用到了並查集的思想,回溯後將此點與其父親節點合併,答案返回集合的父親節點
**示例:
存詢問:
void add_qu(int a,int b,int i)
主體:
void targan(int x)
for(int i=0;i時間複雜度: \(o(n+m)\)
還是貼個完整**吧:
#includeusing namespace std;
const int n=5e5+5,m=n*2;
int h[n],nxt[m],en[m],m;
vectorqu[n],id[n];
int root;
int v[n],ans[n],f[n];
void add(int a,int b)
void add_qu(int a,int b,int i)
int get(int x)
void targan(int x)
for(int i=0;iv[x]=2;
}int main()
for(int i=1;i<=k;i++)
f[root]=root;
targan(root);
for(int i=1;i<=k;i++) printf("%d\n",ans[i]);
return 0;
}
最近公共祖先 LCA 最近公共祖先
直接暴力搜尋參考 普通搜尋每次查詢都需要 樸素演算法是一層一層往上找,倍增的話直接預處理出乙個 具體做法是 維護乙個 的關係來線性求出這個陣列 int anc n 31 int dep n 記錄節點深度 void dfs int u,int parent for int i 0 i g u size...
最近公共祖先 最近公共祖先(LCA)
如題,給定一棵有根多叉樹,請求出指定兩個點直接最近的公共祖先。輸入格式 第一行包含三個正整數n m s,分別表示樹的結點個數 詢問的個數和樹根結點的序號。接下來n 1行每行包含兩個正整數x y,表示x結點和y結點之間有一條直接連線的邊 資料保證可以構成樹 接下來m行每行包含兩個正整數a b,表示詢問...
LCA 最近公共祖先
定義 對於有根樹t的兩個結點u v,最近公共祖先lca t,u,v 表示乙個結點x,滿足x是u v的祖先且x的深度盡可能大。另一種理解方式是把t理解為乙個無向無環圖,而lca t,u,v 即u到v的最短路上深度最小的點。現在給定乙個根為1的樹,求某兩個點的最近公共祖先。思路 預處理出每個點的深度再一...