---
# System prepended metadata

title: Algo｜樹論
tags: [Algo]

---

# 樹論
- [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)


