# 樹論 - [235. Lowest Common Ancestor of a Binary Search Tree](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/submissions/) - [236. Lowest Common Ancestor of a Binary Tree](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/) ## LCA 最近共同祖先 - 例題 : [Kattis – Boxes](https://yuihuang.com/kattis-boxes/) - 先 `O(nlogn)` 建立 dp[x][i] ,代表節點 x 往上走 2^i 部的節點 - dp[x][i] = dp[dp[x][i-1]][i-1] - 可以 `O(logn)` 查詢任意點的任意倍祖先 - 給定兩個節點 u, v,可以 `O(logn)` 找出 LCA ```clike= #include <bits/stdc++.h> using namespace std; vector <int> G[1000]; int dp[1000][20], lvl[1000]; void dfs(int now, int p){ lvl[now] = ~p ? lvl[p] + 1 : 0; dp[now][0] = p; for(int i = 1; (1<<i) <= lvl[now]; i++) dp[now][i] = dp[dp[now][i-1]][i-1]; for(auto &nb:G[now]){ if(nb==p) continue; dfs(nb, now); } } int lca(int u, int v){ if (lvl[u] > lvl[v]) swap(u, v); int dif = lvl[v] - lvl[u]; for (int i = 0; i < 20; i++){ if (dif & 1) v = dp[v][i]; dif >>= 1; } if (u == v) return u; // special case for (int i = 19; i >= 0; i--){ if (dp[u][i] != dp[v][i]){ u = dp[u][i]; v = dp[v][i]; } } return dp[u][0]; // one step away from LCA } int main(){ vector<vector<int>> input = {{0,1},{0,2},{1,3},{1,4},{3,5},{4,6},{6,7},{2,8},{2,9},{8,10}}; for(auto e:input){ G[e[0]].push_back(e[1]); G[e[1]].push_back(e[0]); } dfs(0, -1); for(int i=0;i<=10;i++) for(int j=0;j<=10;j++) cout<<lca(i,j)<<((j==10)?'\n':' '); return 0; } ``` ## 樹鍊剖分 - 一棵樹上進行路徑的修改、求極值、求和 - 把樹拆成一條條重鍊 - [CP Heavy-light decomposition](https://cp-algorithms.com/graph/hld.html)